
LINKSYS AC1900 EA7500v3 IGD UPnP Стековое переполнение буфера удаленное выполнение кода уязвимость
Эта уязвимость позволяет сетевым злоумышленникам, находящимся в той же сети, выполнять произвольный код на уязвимых установках маршрутизаторов LINKSYS EA7500. Для эксплуатации этой уязвимости аутентификация не требуется.
Конкретная ошибка находится в обработке данных HTTP-запроса к службе IGD UPnP. При разборе содержимого переменной, предоставленной пользователем в определенном запросе SOAP UPnP Action, процесс не проверяет должным образом длину пользовательских данных перед их копированием в стековый буфер фиксированной длины. Злоумышленник может использовать эту уязвимость для выполнения кода с правами root.
Продукт/прошивка: Linksys EA7500 Firmware ВСЕ ВЕРСИИ, включая Ver.3.0.1.207964 - Другие модели маршрутизаторов и версии прошивки, использующие этот бинарный файл, также уязвимы
Бинарный файл службы UPnP IGD находится в /usr/sbin/IGD и по умолчанию работает на порту 49152. Эта служба предоставляет файл описания UPnP XML IGDdevicedesc.xml, который описывает несколько функций, которые можно вызывать с помощью HTTP-запросов с XML-телом. Одна из этих функций — SetDefaultConnectionService. Эта функция требует одну переменную строкового типа. При вызове и выполнении функции SetDefaultConnectionService программа не проверяет длину предоставленной пользователем переменной перед выполнением вызова strncpy с этим буфером. Как адрес источника, так и переменные размера копирования в вызове strncpy контролируются пользователем, причем размер копирования равен длине предоставленной пользователем переменной. Затем данные копируются в фиксированный буфер размером 184 байта, что приводит к уязвимости переполнения стекового буфера.
Функция SetDefaultConnectionService помечена как _set_connection_type. Функция начинается с инициализации 184-байтового буфера, а затем получает указатель на буфер, содержащий предоставленную пользователем строковую переменную, включенную в запрос, если она не равна NULL. Это делается с помощью вызова PAL_xml_node_GetFirstbyName, а затем PAL_xml_node_get_value. См. код ниже:
int _set_connection_type(int **param_1)
{
int iVar1;
char *var_value;
size_t var_value_length;
undefined uVar2;
undefined1 *puVar3;
char **ppcVar4;
undefined4 *puVar5;
char *pcVar6;
int *piVar7;
char acStack_d4 [184]; -----> /* Initializing 184-byte buffer */
memset(acStack_d4,0,0xb4);
iVar1 = PAL_xml_node_GetFirstbyName((*param_1)[0xf0],"NewConnectionType",0); -----> /* iVar1 now points to the user-supplied value */
if ((iVar1 != 0) && (var_value = (char *)PAL_xml_node_get_value(), var_value != (char *)0x0)) { -----> /* Ensures the user-supplied value is not empty and obtains a pointer to it */
...
Позже в той же функции выполняется вызов strlen для получения размера предоставленной пользователем строки плюс статическое смещение 0x174. Уязвимое условие срабатывает в последующем вызове strncpy, где аргументом назначения является адрес вновь инициализированного 184-байтового буфера, источником — указатель на предоставленную пользователем строку, а размер операции копирования — размер предоставленной пользователем строки, возвращаемый вызовом strlen, плюс статическое смещение 0x174. Это приводит к уязвимости переполнения буфера, поскольку как адрес источника, так и переменные размера контролируются пользователем, и никакие проверки размера не выполняются. См. код ниже:
int _set_connection_type(int **param_1)
{
...
var_value_length = strlen((char *)(iVar1 + 0x174)); ----> /* iVar1 is a pointer to the user supplied string */
strncpy(acStack_d4,(char *)(iVar1 + 0x174),var_value_length + 1); ----> /* Vulnerable strncpy call */
...
Смещение для перезаписи адреса возврата функции в стеке составляет 276 байт. Следующие 4 байта можно использовать для перенаправления выполнения на произвольный адрес и, таким образом, перехвата потока управления программы.
Использовать более безопасную функцию копирования строк: Вместо использования strncpy, которая не гарантирует нуль-терминацию целевого буфера, можно использовать более безопасную функцию копирования строк, например strncpy_s или memcpy_s. Эти функции гарантируют, что целевой буфер всегда будет завершаться нулем, и не позволяют копировать больше данных, чем может вместить буфер.
Проверка входных данных: Проверять пользовательский ввод, чтобы убедиться, что он не превышает размер целевого буфера. Если ввод длиннее размера буфера, либо отклонять его, либо обрезать до размера буфера.
Использовать динамически выделяемый буфер: Выделять память для целевого буфера динамически вместо использования стекового буфера фиксированного размера. Этот подход позволяет регулировать размер буфера в соответствии с размером входных данных. (Не рекомендуется для системы с ограниченными ресурсами)
Выполнение PoC: python poc.py 192.168.1.1 49152
Ссылка для скачивания ПО: https://support.linksys.com/kb/article/559-en/ (Версия прошивки Ver. 3.0.1.207964)
gdbserver-7.7.1-armel-eabi5-v1-sysv, доступный здесь: https://github.com/stayliv3/gdb-static-cross/tree/master/prebuilt).pkill IGD, чтобы завершить бинарный файл, а затем перезапустите его с помощью ./gdbserver :1337 /usr/sbin/IGD. Следующий файл .gdbinit можно использовать для запуска стабильного сеанса отладки:> set follow-fork-mode child
> set detach-on-fork off
> target remote 192.168.1.1:1337
> c