HTTP based detection of Axis devices.
# 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.114027");
script_version("2023-10-24T05:06:28+0000");
script_tag(name:"last_modification", value:"2023-10-24 05:06:28 +0000 (Tue, 24 Oct 2023)");
script_tag(name:"creation_date", value:"2018-08-29 10:46:20 +0200 (Wed, 29 Aug 2018)");
script_tag(name:"cvss_base", value:"0.0");
script_tag(name:"cvss_base_vector", value:"AV:N/AC:L/Au:N/C:N/I:N/A:N");
script_tag(name:"qod_type", value:"remote_banner");
script_name("Axis Devices Detection (HTTP)");
script_tag(name:"summary", value:"HTTP based detection of Axis devices.");
script_category(ACT_GATHER_INFO);
script_copyright("Copyright (C) 2018 Greenbone AG");
script_family("Product detection");
script_dependencies("find_service.nasl", "httpver.nasl", "global_settings.nasl");
script_require_ports("Services/www", 80);
script_exclude_keys("Settings/disable_cgi_scanning");
exit(0);
}
include("host_details.inc");
include("http_func.inc");
include("http_keepalive.inc");
include("port_service_func.inc");
include("misc_func.inc");
port = http_get_port( default:80 );
is_axis_os = FALSE;
version = "unknown";
model = "unknown";
full_name = "unknown";
install = "/";
concluded = "";
conclUrl = "";
url = "/";
res = http_get_cache( port:port, item:url );
# AXIS M2036-LE Bullet Camera Device:
# <html><head><meta http-equiv="refresh" content="0; URL=/camera/index.html" /></head></html>
#
# AXIS Q6135-LE PTZ Network Camera:
# <meta http-equiv="refresh" content="0; URL=/aca/index.html" />
#
if ( res =~ '<meta http-equiv="refresh" content="0; URL=' ) {
url_reg = eregmatch( pattern:'URL=([^"]+)"', string:res );
if ( ! isnull( url_reg[1] ) ) {
url = url_reg[1];
res = http_get_cache( port:port, item:url );
}
}
# AXIS A8207-VE Mk II Network Video Door Station:
# window.location.pathname='intercom/index.html'
if ( res =~ "intercom/index\.html" ) {
# nb: Following redirect first to make sure it is an AXIS device
url = "/intercom/index.html";
res = http_get_cache( port:port, item:url );
}
# Companion Eye mini L:
# <title>AXIS</title>
#
# AXIS Q6128-E PTZ Dome Network Camera:
# <title>Index page</title>
# var refreshUrl = "/view/view.shtml?id=13";
#
if ( res =~ "^HTTP/(1\.[01]|2) 200" && ( res =~ "<title>.*AXIS.*</title>" ||
( res =~ "<title>Index page</title>" && res =~ "/view/view\.shtml" ) ) ) {
# nb: This are older versions of AXIS OS, 6.50.x and will not be detected by the other methods,
# but this can also lead to false positives so we need to double check the version
# eg. AXIS Q8414-LVS Fixed Network Camera
if ( res =~ "<title>Index page</title>" )
check_vers = TRUE;
# nb: For some reason P1364 cameras does not reply to any of the AXIS OS tests but this rule can be safely applied
# Other devices have the same issue
if ( res =~ "Axis Communications AB" && res =~ "<title>AXIS</title>" )
is_axis_os = TRUE;
# <TITLE>Live view / - AXIS 205 version 4.03</TITLE>
mod = eregmatch( pattern:"AXIS ([-0-9A-Za-z. ]+) version ([0-9.]+)(</title>|</TITLE>)", string:res );
if ( ! isnull( mod[1] ) ) {
found = TRUE;
model = mod[1];
full_name = "AXIS " + model;
concluded = " " + mod[0];
conclUrl = " " + http_report_vuln_url( port:port, url:url, url_only:TRUE );
if ( ! isnull( mod[2] ) ) {
version = mod[2];
}
} else {
conclUrl = " " + http_report_vuln_url( port:port, url:url, url_only:TRUE );
url = "/axis-cgi/basicdeviceinfo.cgi";
data = '{"apiVersion":"1.2","method":"getAllUnrestrictedProperties"}';
req = http_post_put_req( port:port, url:url, data:data, add_headers:make_array( "Accept-Encoding", "gzip, deflate" ) );
# {"apiVersion": "1.3", "data": {"propertyList": {"ProdNbr": "Q6315-LE", "HardwareID": "7C9.2", "ProdFullName": "AXIS Q6315-LE PTZ Network Camera",
# "Version": "10.11.87", "ProdType": "PTZ Network Camera", "Brand": "AXIS", "WebURL": "http://www.axis.com", "ProdVariant": "",
# "SerialNumber": "B8A44F5B6CEF", "ProdShortName": "AXIS Q6315-LE", "BuildDate": "Jun 16 2022 20:01"}}}
res = http_keepalive_send_recv( port:port, data:req );
# nb: The presence of the API is for the time being the best indicator that this is AXIS OS.
if ( res =~ "^HTTP/(1\.[01]|2) 200" || res =~ "Unauthorized" )
is_axis_os = TRUE;
if ( ! res || res !~ "^HTTP/(1\.[01]|2) 200" ) {
url = "/axis-cgi/prod_brand_info/getbrand.cgi";
# {
# "Brand": {
# "Brand": "AXIS",
# "ProdType": "Network Camera",
# "ProdNbr": "M1125",
# "ProdShortName": "AXIS M1125",
# "ProdFullName": "AXIS M1125 Network Camera"
# }
# }
res = http_get_cache( port:port, item:url );
}
if ( res && res =~ "^HTTP/(1\.[01]|2) 200" && res =~ '"Brand":( )*"AXIS"' && '"ProdFullName":' >< res && '"ProdNbr":' >< res ) {
found = TRUE;
# nb: It seems that the CPEs used by NIST follow the pattern provided by this field. Nevertheless, it is not always present, thus the fallback.
# "ProdShortName": "AXIS Companion Eye mini L"
mod = eregmatch( pattern:'"ProdShortName":\\s*"([-A-Za-z0-9 ]+)"', string:res );
if ( ! mod ) {
# "ProdNbr": "Q6315-LE",
# "ProdNbr": "C Eye mini L",
mod = eregmatch( pattern:'"ProdNbr":\\s*"([-A-Za-z0-9 ]+)"', string:res );
}
if ( ! isnull( mod[1] ) ) {
model = mod[1];
concluded = " " + mod[0];
conclUrl += '\n ' + http_report_vuln_url( port:port, url:url, url_only:TRUE );
# "ProdFullName": "AXIS Q6315-LE PTZ Network Camera"
# "ProdFullName": "AXIS Companion Eye mini L Network Camera"
full_mod = eregmatch( pattern:'"ProdFullName":\\s*"([-A-Za-z0-9 ]+)"', string:res );
if ( ! isnull( full_mod[1] ) ) {
full_name = full_mod[1];
concluded += '\n ' + full_mod[0];
}
}
# nb: Last tentative to differentiate between AXIS OS and dedicated firmware
if ( ! is_axis_os ) {
url = "/axis-cgi/apidiscovery.cgi";
data = '{"apiVersion":"1.0","method":"getApiList"}';
req = http_post_put_req( port:port, url:url, data:data, add_headers:make_array( "Accept-Encoding", "gzip, deflate" ) );
res = http_keepalive_send_recv( port:port, data:req );
# nb: The presence of the API is for the time being the best indicator that this is AXIS OS.
# But this is not present for all AXIS OS versions
if ( res =~ "^HTTP/(1\.[01]|2) 200" || res =~ "Unauthorized" )
is_axis_os = TRUE;
}
}
}
}
if ( ! found ) {
# nb: Video Server devices have both index2.shtml and view.shtml but only have the model in the index2.shtml title
url = "/view/index2.shtml";
res = http_get_cache( port:port, item:url );
if ( ! res || res !~ "^HTTP/(1\.[01]|2) 200" ) {
url = "/view/view.shtml";
res = http_get_cache( port:port, item:url );
}
# <TITLE>AXIS 2400 Video Server</TITLE>
# <title>AXIS A8004-VE Network Video Door Station</title>
# <title>Live view - AXIS 233D Network Dome Camera</title>
# <title>Live view / - AXIS 205 Network Camera version 4.05</title>
if ( res && res =~ "^HTTP/(1\.[01]|2) 200" && ( res =~ "<title>Live view.*AXIS" || res =~ "<title>AXIS" ) ) {
mod = eregmatch( pattern:"(AXIS [-0-9A-Za-z. ]+)(</title>|</TITLE>)", string:res );
if ( mod[1] ) {
found = TRUE;
model_full = mod[1];
# <title>Live view / - AXIS 205 Network Camera version 4.05</title>
if ( " version " >< model_full ) {
split_mod = split( model_full, sep:" version ", keep:FALSE );
model = split_mod[0];
model_full = model;
if ( split_mod[1] )
version = split_mod[1];
} else
model = model_full;
full_name = model_full;
# nb: NVD uses CPE like cpe:/h:axis:2400_video_server or cpe:/o:axis:2100_network_camera_firmware
if ( "Network Camera" >!< model && "Video Server" >!< model ) {
split_mod = split( model, sep:" ", keep:FALSE );
model = split_mod[0];
}
conclUrl = " " + http_report_vuln_url( port:port, url:url, url_only:TRUE );
concluded += " " + mod[0];
}
}
}
if ( found ) {
if ( ! version || version == "unknown" ) {
url2 = "/axis-release/releaseinfo";
req = http_get_req( port:port, url:url2, add_headers:make_array( "Accept-Encoding", "gzip, deflate" ) );
res2 = http_keepalive_send_recv( port:port, data:req );
#version:"1.27.24.15"
vers = eregmatch( pattern:"version:\s*([0-9.]+)", string:res2 );
if ( vers[1] ) {
version = vers[1];
conclUrl += '\n ' + http_report_vuln_url( port:port, url:url2, url_only:TRUE );
concluded += '\n ' + vers[0];
# nb: This is a hack to make a distinction between first AXIS OS versions and non AXIS OS firmware
if ( check_vers && version =~ "^6\.5" )
is_axis_os = TRUE;
}
}
if ( model =~ "^AXIS " )
model = substr( model, 5 );
set_kb_item( name:"axis/device/detected", value:TRUE );
set_kb_item( name:"axis/device/axisos", value:is_axis_os );
set_kb_item( name:"axis/device/http/detected", value:TRUE );
set_kb_item( name:"axis/device/http/port", value:port );
set_kb_item( name:"axis/device/http/" + port + "/model", value:model );
set_kb_item( name:"axis/device/http/" + port + "/modelName", value:full_name );
set_kb_item( name:"axis/device/http/" + port + "/version", value:version );
if ( concluded )
set_kb_item( name:"axis/device/http/" + port + "/concluded", value:chomp( concluded ) );
if ( conclUrl )
set_kb_item( name:"axis/device/http/" + port + "/concludedUrl", value:conclUrl );
}
exit( 0 );