Introduction


With todays rising complexity in IT environments, we are busy building new virtualization layers over layers. High pressure is put on the most basic IT infrastructure service delivery, including sound server hardware management. The cost and size reduction for modern servers lead to large-scale, rapid and often automated deployments. Mistakes in that deployment, which formerly impacted single systems, can now impact whole datacenters.

One potentially fatal mistake is to connect the server's management console into an end-user reachable network, unconfigured and without further protection. It may sound incredible, but in a real-life case, several dozens of PRD servers turned out to be accessible that way.

A new login screen appearing in the users browser, a short Google for default and voila, product name phrases such as "Lights Out" could become a whole different meaning...

Security teams were unable to identify all these systems, rummaging through incomplete inventory lists and blindly poking around. A simple script was written to help identify the highest risk server management console systems - those giving immediate access through the vendor-provided default credentials.

But before we look at code, a very brief introduction...

History


A server console is necessary to configure the server hardware for its deployment: setting the operating system boot device, enabling/disabling network ports, adding storage on a low level. In its most basic use, it also allows to diagnose hardware problems and to power-cycle the system.


Cyclades TS400
Terminal Server, ca 2003

For a long time, server console access was provided through serial ports, and accessed with terminal software. When server numbers rose and remote access became necessary, server console ports were aggregated into so-called "terminal servers", which created the boundary between the serial lines and the Ethernet network. Because console software was always very basic and offered no protection, system administrators used to guard the access to all consoles and their extension: terminal servers, very, very strongly.

Modern Server Management


Following the general IT trend of protocol convergence and standardization, modern server management console systems are now directly accessible through high-speed Ethernet network ports with assigned IP's. On these management interfaces, the server hardware console became a web-based application, running on a SSL-enabled webserver on top of a separate, embedded mini-OS. In addition to letting the adminstrator control server hardware through this web interface, addtional methods such as terminal-based SSH, SNMP or IPMI could allow the execution of critical functions like system Shutdown, Reboot, Boot Image Flash, or changing the Boot Device.

Below is a short overview of hardware console systems used in the most commonly deployed Wintel server platforms:

Dell DRAC/iDRAC

Dell calls its server management console (i)DRAC, which stands for "Dell Remote Access Console". A little "i" in front means it is integrated, the server has it built-in. Point your browser to the management IP with "https", and with luck the default combination for Dells current iDRAC version 6, "root/calvin" will let you in.

Cisco CIMC

Cisco, the networking company who only recently became a major server vendor with its UCS lineup, calls its management console CIMC - "Cisco Integrated Management Controller". Although the graphics design is different, technically it is similar to Dells DRAC above. It certainly comes with default credentials. Ciscos CIMC up to version 2.0 uses "admin/password".

Hewlett Packard iLO

Hewlett Packard calls its server management console "iLO" - "integrated Lights-Out", and ships it with the ProLiant server product line. The default user for HP's iLO to version 2.0 is "Administrator". Contrary to Dell and Cisco, HP decided against a common default password and uses the servers individual serial number, found on a sticker or device tag. This is better then using standard defaults, because it restricts even the initial login to a person with physical access to the server itself.

Verification Approach


To identify unprotected server consoles, a Perl script (download) such as listed below could be used under Linux, Unix or even Windows (if a Perl interpreter such as ActiveState is installed). It will check a network range, IP-by-IP. It can also serve as a programming example for Perls LWP module, showing the possibility and limits in dealing with the complexity of emulating a web client.

#!C:\Program Files\perl\bin\Perl.exe -w
# ------------------------------------------------------------ #
# check_console_defaults.pl v1.0 20121028 frank4dd  GPLv3      #
#                                                              #
# This script checks for reachable server management console   #
# systems. Access to these systems should be restricted, and   #
# default user passwords should have been changed immediately. #
#                                                              #
# Currently identifies iDRAC v6, CIMC v1.2 and iLO v2          #
# HP uses the serial printed on the servers service tag, since #
# we don't know the HP serial, there is no login function...   #
# ------------------------------------------------------------ #
use Net::Ping;
use LWP::UserAgent;

# ------------------------------------------------------------ #
# Below is the network range we will verify. This is typically #
# a class-C network, sometimes a smaller subnet range. We give #
# the values on the command line, but we could also hardcode.. #
# my $basenet = "192.168.240";                                 #
# my $start_host = 1;                                          #
# my $end_host = 25;                                           #
# ------------------------------------------------------------ #
$num_args = $#ARGV + 1;
if ($num_args != 3) {
  print "Usage: check_console_defaults.pl [network-base] [start_ip] [end_ip]\n\n";
  print "Example: check_console_defaults.pl 192.168.1 20 44\n";
  print "This will run the check on these IP's: 192.168.1.20-44.\n";
  exit -1;
}

my $basenet=$ARGV[0];
my $start_host=$ARGV[1];
my $end_host=$ARGV[2];

# ------------------------------------------------------------ #
# Below are the HTML signatures for server management console  #
# systems. The script checks 3 vendors: Cisco, Dell and HP as  #
# the most commonly available server vendors in the industry.  #
#                                                              #
# Cisco is simple, because we get a login page right away.     #
# Dell is tricky, because the initial response is a empty page #
# containing a conditional javasacript redirect to support SSO.#
# ------------------------------------------------------------ #
my $cimc_id = "<title>Cisco Integrated Management Controller Login</title>";
my $idrac_id = "          top.document.location.href = \"/sclogin.html\";";
my $hpilo_id = "<TITLE>HP Integrated Lights-Out 2 Login</TITLE>";

my $host = $start_host;
while($host<=$end_host) {
  $ip = $basenet.".".$host;
  print "Checking $ip... ";

  # ------------------------------------------------------------ #
  # Before checking the web interface, we first ping the host to #
  # ensure it exists. Otherwise, the web check 'hangs' and waits #
  # with a long, hard to interrupt timeout. Our ping timeout is  #
  # set to 1 second only, providing a fast scan (ptimeout = 1;). #
  # ------------------------------------------------------------ #
  my $p=Net::Ping->new('icmp');
  my $ptimeout = 1;
  if ($p->ping($ip, $ptimeout)) {
    print "Host $ip alive... ";
  } else {
    print "Host does not exist.\n";
    $host++;
    next;
  }
  $p->close();

  # ------------------------------------------------------------ #
  # All modern remote management console systems run under SSL,  #
  # in 99.9% using the default selfsigned certs. We ignore them. #
  # Cisco CIMC web interface delivers content with compression,  #
  # we need to accept & handle the gzip-encoded server response. #
  # ------------------------------------------------------------ #
  my $ua = LWP::UserAgent->new(ssl_opts =>{verify_hostname => 0});
  $ua->timeout(2);
  my $can_accept = HTTP::Message::decodable;

  my $https_url = "https://".$ip."/";
  my $ssl_response = $ua->get($https_url, 'Accept-Encoding' => $can_accept,);

  if(! $ssl_response->is_success) {
    print "No SSL web page found.\n";
    $host++;
    next;
  }

  # debug
  #print "\n".$ssl_response->decoded_content."\n";

  if($ssl_response->decoded_content =~ m/$cimc_id/i) {
    print "CIMC found! ";
    &check_cimc_login;
  }
  elsif($ssl_response->decoded_content =~ m/$idrac_id/i) {
    print "iDrac found! ";
    &check_idrac_login;
  }
  elsif($ssl_response->decoded_content =~ m/$hpilo_id/i) {
    print "HP iLO found! ";
  }
  else {
    print "SSL Web page is not console mgmt.";
  }
  print "\n";
  $host++;
}

# ------------------------------------------------------------ #
# CIMC login function to check access with default values      #
# Cisco CIMC default: admin/password         works... :-)      #
# ------------------------------------------------------------ #
sub check_cimc_login {

  # ----------------------------------------------------------- #
  # The login attempt returns one of these two xml responses:   #
  # ----------------------------------------------------------- #
  my $login_ok =   "<authResult>0</authResult> <forwardUrl>index.html</forwardUrl> </root>";
  my $login_fail = "<authResult>1</authResult> <forwardUrl>index.html</forwardUrl>  <errorMsg></errorMsg></root>";
  my $ua = LWP::UserAgent->new(ssl_opts =>{verify_hostname => 0});
  $ua->timeout(2);
  my $can_accept = HTTP::Message::decodable;

  my $login_url = "https://".$ip."/data/login";
  my $login_res = $ua->post( $login_url, { 'user' => 'admin', 'password' => 'password' } );
  my $logindata = $login_res->decoded_content();

  # debug
  # print "\n".$logindata."\n";

  if($logindata =~ m/$login_ok/) {
    print "...Default Login success!";
  }
  elsif($logindata =~ m/$login_fail/) {
    print "...Default Login failed.";
  }
  else {
    print "Unknown response.";
  }
}

# ------------------------------------------------------------ #
# This login function checks the iDRAC default password access.#
# Incidentally, the function is *very* similar to Cisco. DELL  #
# was first, so maybe Cisco engineers were doing some re-eng   #
# when they build their CIMC? Javascript looks copy&paste...   #
# Dell iDRAC default: root/calvin               works... :-)   #
# ------------------------------------------------------------ #
sub check_idrac_login {

  # ----------------------------------------------------------- #
  # The login attempt returns one of these two xml responses:   #
  # ----------------------------------------------------------- #
  my $login_ok =   "<authResult>0</authResult> <forwardUrl>index.html</forwardUrl> </root>";
  my $login_fail = "<authResult>1</authResult> <forwardUrl>index.html</forwardUrl>  <errorMsg></errorMsg></root>";

  my $ua = LWP::UserAgent->new(ssl_opts =>{verify_hostname => 0});
  $ua->timeout(2);
  my $can_accept = HTTP::Message::decodable;
  my $login_url = "https://".$ip."/data/login";

  # ----------------------------------------------------------- #
  # here we make the HTTP request, using DELL's default values: #
  # ----------------------------------------------------------- #
  my $login_res = $ua->post( $login_url, Content => 'user=root&password=calvin' );
  my $logindata = $login_res->decoded_content();

  # debug
  # print "\n".$logindata."\n";

  if($logindata =~ m/$login_ok/) {
    print "...Default Login success!";
  }
  elsif($logindata =~ m/$login_fail/) {
    print "...Default Login failed.";
  }
  else {
    print "Unknown response.";
  }
}

Exemplary Results


The example script run below shows how it could look in action. For each tested IP in the given range, it validates four stages:

  1. if a system answers under this IP, using ping
  2. if a SSL website exists
  3. if the SSL web response matches a server console signature
  4. if the login with default username and password is possible

Depending on the number of live hosts and console screens found, execution on a class-C takes would take about 5~20 minutes.

D:\Code> check_console_defaults.pl 192.168.24 1 254
...
Checking 192.168.24.3... Host does not exist.
Checking 192.168.24.4... Host 192.168.24.4 alive... CIMC found! ...Default Login success!
Checking 192.168.24.5... Host 192.168.24.5 alive... CIMC found! ...Default Login success!
Checking 192.168.24.6... Host 192.168.24.6 alive... CIMC found! ...Default Login failed.
Checking 192.168.24.7... Host does not exist.
Checking 192.168.24.8... Host does not exist.
Checking 192.168.24.9... Host does not exist.
Checking 192.168.24.10... Host 192.168.24.10 alive... iDrac found! ...Default Login success!
Checking 192.168.24.11... Host does not exist.
Checking 192.168.24.12... Host 192.168.24.12 alive... iDrac found! ...Default Login success!
Checking 192.168.24.13... Host 192.168.24.13 alive... iDrac found! ...Default Login failed.
Checking 192.168.24.14... Host 192.168.24.14 alive... iDrac found! ...Default Login failed.
Checking 192.168.24.15... Host does not exist.
...
Checking 192.168.24.76... Host does not exist.
Checking 192.168.24.77... Host 192.168.24.77 alive... No SSL web page found.
Checking 192.168.24.78... Host 192.168.24.78 alive... No SSL web page found.
Checking 192.168.24.79... Host does not exist.
Checking 192.168.24.80... Host does not exist.
...

The script, while being far from perfect, is free and easily adaptable to identify other, similar web defaults. Please share your adaption, but refrain from adding any malicous functions (i.e. "Power Off"), however tempting it might be...

Yes, all the cool, professional $$$ security scanners could probably do the same. Appearantly, our security teams were not able to use them. If anybody has a simple guide to post here, how about it: Foundstone? Qualys?

While currently working in IT audit, our professionally provided tools consist of Word, Excel, and Powerpoint. It would probably help the profession if above script could be coded as a MS-Office macro, ideally with output into Excel. Seriously.

I am publishing this information in detail when I noticed this is not a one-off oversight, but a re-occuring case over several months. I became strongly concerned this topic affects a wide audience. Outsourcing, cost reduction, task automation and staffing shortages are common - Any experiences?

If this script runs under Windows 7, local admin rights are required to for Perl to open ICMP sockets. Open the commandline console with right-click, selecting "Run as administrator".

Source:

Vendor Links: