Lucene search

K
openvasCopyright (C) 2018 Greenbone AGOPENVAS:1361412562310114047
HistoryNov 12, 2018 - 12:00 a.m.

Samsung Web Viewer DVR Default Credentials (HTTP)

2018-11-1200:00:00
Copyright (C) 2018 Greenbone AG
plugins.openvas.org
56

7.6 High

AI Score

Confidence

Low

The remote installation of Samsung Web Viewer DVR is using known
and default credentials for the web interface.

# SPDX-FileCopyrightText: 2018 Greenbone AG
# 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-only

if(description)
{
  script_oid("1.3.6.1.4.1.25623.1.0.114047");
  script_version("2023-07-20T05:05:18+0000");
  script_tag(name:"cvss_base", value:"9.0");
  script_tag(name:"cvss_base_vector", value:"AV:N/AC:L/Au:N/C:C/I:P/A:P");
  script_tag(name:"last_modification", value:"2023-07-20 05:05:18 +0000 (Thu, 20 Jul 2023)");
  script_tag(name:"creation_date", value:"2018-11-12 19:25:24 +0100 (Mon, 12 Nov 2018)");
  script_category(ACT_ATTACK);
  script_copyright("Copyright (C) 2018 Greenbone AG");
  script_family("Default Accounts");
  script_name("Samsung Web Viewer DVR Default Credentials (HTTP)");
  script_dependencies("gb_samsung_web_viewer_dvr_detect.nasl", "gb_default_credentials_options.nasl");
  script_require_ports("Services/www", 80);
  script_mandatory_keys("samsung/web_viewer/dvr/detected");
  script_exclude_keys("default_credentials/disable_default_account_checks");

  script_xref(name:"URL", value:"https://customvideosecurity.com/blog/tag/default-password-axis/");

  script_tag(name:"summary", value:"The remote installation of Samsung Web Viewer DVR is using known
  and default credentials for the web interface.");

  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 installation of Samsung Web Viewer DVR is lacking a proper
  password configuration, which makes critical information and actions accessible to anyone.");

  script_tag(name:"vuldetect", value:"Checks if a successful login to Samsung Web Viewer DVR is possible.");

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

  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("string_hex_func.inc");
include("http_func.inc");
include("http_keepalive.inc");
include("dump.inc");

CPE = "cpe:/a:samsung:web_viewer_dvr";

if(!port = get_app_port(cpe: CPE, service: "www"))
  exit(0);

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

#Because we can't use multiple keys, the first part(key) is the password and the second part(value) is the username.
creds = make_array("4321", "admin",
                   "111111", "admin",
                   "admin", "root");

url = "/cgi-bin/webviewer_login_page?loginvalue=0&port=0";
loginUrl = "/cgi-bin/webviewer_cgi_login2";

res = http_get_cache(port: port, item: url);

func = eregmatch(pattern: "(function [sS]et[Cc]ookie\(\)\{[^\}]+\})", string: res);
if(isnull(func[1])) exit(99);
funcSetCookie = func[1];

#Identification of the host's specific authentication mechanism based on the source code
if("document.login_page_submit.data2.value = do_encrypt(document.login_page.data2.value);" >< funcSetCookie) {
  authType = "RSA";
}
else if("document.login_page_submit.data2.value = sha256_digest(document.login_page.data2.value);" >< funcSetCookie) {
  authType = "SHA256"; #Values are random
}
else if("'&PWD='+encode64(document.login_page.pwd.value)" >< funcSetCookie) {
  authType = "Base64";
  loginUrl = "/cgi-bin/webviewer_cgi_login";
}
else if("document.login_page_submit.data2.value = hex_func_five(document.login_page.data2.value);" >< funcSetCookie) {
  authType = "MD5";
}
else {
  exit(99);
}

foreach cred(keys(creds)) {

  #To avoid confusion with previous scripts, because of the reversed order:
  username = creds[cred];
  password = cred;

  #GET request to acquire current random values if they are provided
  req = http_get_req(port: port, url: url);
  res = http_send_recv(port: port, data: req);

  func = eregmatch(pattern: "(function [sS]et[Cc]ookie\(\)\{[^\}]+\})", string: res);
  #No need to check, it is guaranteed to match at this point.
  funcSetCookie = func[1];

  #Generation of random values for data3
  #Case1: Value has to be generated by the user
  if("document.login_page_submit.data3.value = val_rand;" >< funcSetCookie) {
    data3Num = "0." + rand_str(charset: "0123456789", length: 16);
  } #Case 2: Value can be extracted
  else if((randNum = eregmatch(pattern: "document.login_page_submit.data3.value\s*=\s*([0-9.]+);", string: funcSetCookie)) && authType != "RSA") {
    data3Num = randNum[1];
  } #Case 3: Value has to be generated by the user and was expected in the url from before
  else if("document.login_page_submit.data3.value" >< funcSetCookie) { #Value can be extracted
    data3Num = "0." + rand_str(charset: "0123456789", length: 16);
  } #Case 4: None of the criteria apply - just generate a random number
  else {
    data3Num = "0." + rand_str(charset: "0123456789", length: 16);
  }
  if(authType == "RSA") {
    #Generation of random values for data4
    #Case 1: Value has to be generated by the user
    if("document.login_page_submit.data4.value = val_rand;" >< funcSetCookie) {
      data4Num = "0." + rand_str(charset: "0123456789", length: 16);
    } #Case 2: Value can be extracted
    else if(randNum = eregmatch(pattern: "document.login_page_submit.data4.value\s*=\s*([0-9.]+);", string: funcSetCookie)) {
      data4Num = randNum[1];
    } #Case 3: Value has to be generated by the user and was expected in the url from before
    else if("document.login_page_submit.data4.value" >< funcSetCookie) { #Value can be extracted
      data4Num = "0." + rand_str(charset: "0123456789", length: 16);
    } #Case 4: None of the criteria apply - just generate a random number
    else {
      data4Num = "0." + rand_str(charset: "0123456789", length: 16);
    }
  }

  if(authType == "RSA") {

    # nb: Available since r25570 of libs 9.0
    if(!defined_func("rsa_public_encrypt")) exit(0);

    #Acquiring both the RSA modulus based on our random string, as well as the RSA exponent
    url = "/cgi-bin/webviewer_login_page?lang=en&loginvalue=3&port=0&data3=" + data3Num;

    req = http_get_req(port: port, url: url, add_headers: make_array("Accept-Encoding", "gzip, deflate",
                                                                     "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"));

    res = http_keepalive_send_recv(port: port, data: req);

    #var rsa_modulus='CB21A70D02393C18CD551468E473A06DD85EA13C91CF51CAB5A39C1E33B1C62B55E7B10D2A4BD304B69C2C11CF84EF3CB36E30DB6CA0D0CC0C68E63B17C3293F';
    modu = eregmatch(pattern: "var rsa_modulus='([0-9a-fA-F]+)';", string: res);
    if(isnull(modu[1]))
      continue;

    #This is due to hex2raw stripping the first character from uneven strings for some reason.
    #We need to make the string of even length.
    if(strlen(modu[1]) % 2) {
      #Just prepend a 0-character, which does not change the raw value of this string overall.
      #This is a workaround until hex2raw has been modified.
      modu[1] = '0' + modu[1];
    }
    rsa_modulus = hex2raw(s: modu[1]);

    #var rsa_exponent='010001';
    exp = eregmatch(pattern: "var rsa_exponent='([0-9]+)';", string: res);
    if(isnull(exp[1]))
      continue;

    #This is due to hex2raw stripping the first character from uneven strings for some reason.
    #We need to make the string of even length.
    if(strlen(exp[1]) % 2) {
      #Just prepend a 0-character, which does not change the raw value of this string overall.
      #This is a workaround until hex2raw has been modified.
      exp[1] = '0' + exp[1];
    }
    rsa_exponent = hex2raw(s: exp[1]);

    #<input type=hidden name=remote_addr value=1.2.3.4>
    rem_addr = eregmatch(pattern: "<input type=hidden name=remote_addr\s*value=([0-9.]+)>", string: res);
    if(isnull(rem_addr[1])) continue;
    remote_address = rem_addr[1];

    #Note: Change 'pad: "TRUE"' to 'pad: TRUE' once GVM 9 is retired!
    pass = hexstr(rsa_public_encrypt(data: password, e: rsa_exponent, n: rsa_modulus, pad: "TRUE"));

    data = "lang=en&port=0&close_user_session=0&data1=" + base64(str: username) + "%3D&data2=" + pass + "&data3=" + data3Num + "&data4=" + data4Num + "&remote_addr=" + remote_address;

    req = http_post_put_req(port: port, url: loginUrl, data: data, add_headers: make_array("Accept-Encoding", "gzip, deflate",
                                                                                       "Cache-Control", "max-age=0",
                                                                                       "Upgrade-Insecure-Requests", "1",
                                                                                       "Content-Type", "application/x-www-form-urlencoded",
                                                                                       "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"));
    res = http_send_recv(port: port, data: req);
  }
  else if(authType == "SHA256") {
    #<input type=hidden name=remote_addr value=1.2.3.4>
    rem_addr = eregmatch(pattern: "<input type=hidden name=remote_addr\s*value=([0-9.]+)>", string: res);
    if(isnull(rem_addr[1])) continue;
    remote_address = rem_addr[1];

    #lang=en&port=0&close_user_session=0&data1=YWRtaW4%3D&data2=...SHA256(password)&data3=0.34000497427989473&data4=0.34000497427989473&remote_addr=1.2.3.4
    data = "lang=en&port=0&close_user_session=0&data1=" + base64(str: username) + "%3D&data2=" + hexstr(SHA256(password))
    + "&data3=" + data3Num + "&data4=" + data3Num + "&remote_addr=" + remote_address;

    req = http_post_put_req(port: port, url: loginUrl, data: data, add_headers: make_array("Accept-Encoding", "gzip, deflate",
                                                                                       "Cache-Control", "max-age=0",
                                                                                       "Upgrade-Insecure-Requests", "1",
                                                                                       "Content-Type", "application/x-www-form-urlencoded",
                                                                                       "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"));
    res = http_send_recv(port: port, data: req);
  }
  else if(authType == "Base64") {
    #The sessionID is data3 or 4
    #close_user_session=0&lang=en&port=0&id=admin&pwd=4321
    data = "close_user_session=0&lang=en&port=0&id=" + username + "&pwd=" + password;

    #ID=YWRtaW4=&PWD=NDMyMQ==&SessionID=0.5762652428478185
    auth =  "ID=" + base64(str: username) + "=&PWD=" + base64(str: password) + "==&SessionID=" + data3Num;

    req = http_post_put_req(port: port, url: loginUrl, data: data, add_headers: make_array("Accept-Encoding", "gzip, deflate",
                                                                                       "Cache-Control", "max-age=0",
                                                                                       "Upgrade-Insecure-Requests", "1",
                                                                                       "Content-Type", "application/x-www-form-urlencoded",
                                                                                       "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
                                                                                       "Cookie", auth));
    res = http_send_recv(port: port, data: req);
  }
  else if(authType == "MD5") {
    #lang=en&port=0&close_user_session=0&data1=YWRtaW4%3D&data2=21232f297a57a5a743894a0e4a801fc3
    data = "lang=en&port=0&close_user_session=0&data1=" + base64(str: username) + "%3D&data2=" +  hexstr(MD5(password));

    #DATA1=YWRtaW4=&DATA2=YWRtaW4=&SDATA3=0.4896536714730517
    auth = "DATA1=" + base64(str: username) + "&DATA2=" + base64(str: password) + "&SDATA3=" + data3Num;

    req = http_post_put_req(port: port, url: loginUrl, data: data, add_headers: make_array("Accept-Encoding", "gzip, deflate",
                                                                                       "Cache-Control", "max-age=0",
                                                                                       "Upgrade-Insecure-Requests", "1",
                                                                                       "Content-Type", "application/x-www-form-urlencoded",
                                                                                       "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
                                                                                       "Cookie", auth));
    res = http_send_recv(port: port, data: req);
  }

  if(res =~ "top.document.location.href='../index.htm\?port=[0-9]+';" && res !~ "<\s*body\s*onload\s*=\s*'movetoauth\(\)'\s*>") {
    VULN = TRUE;
    report += '\nusername: "' + username + '", password: "' + password + '"';
  }
}

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

exit(99);

7.6 High

AI Score

Confidence

Low