CVE-2025-44018
A firmware downgrade vulnerability exists in the OTA Update functionality of GL-Inet GL-AXT1800 4.7.0. A specially crafted .tar file can lead to a firmware downgrade. An attacker can perform a man-in-the-middle attack to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
GL-Inet GL-AXT1800 4.7.0
GL-AXT1800 - https://www.gl-inet.com/products/gl-axt1800/
8.3 - CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H
CWE-295 - Improper Certificate Validation
The GL-Inet Slate AX (GL-AXT1800) is a pocket-sized travel router with Gigabit speeds and Wi-Fi 6 capabilities. Featuring a variety of VPN and remote connection tools out of the box, the Slate AX is an extremely popular solution for people wanting security on the go and is one of the most popular travel routers in online retailers such as Amazon.
When logging into the web management interface of the GL-Inet Slate AX travel router, the newly logged-in user is sometimes presented with a prompt to upgrade the device, both depending on if there is an upgrade available, and also depending on the version of the device. Regardless, upon checking the actual upgrade webpage, the device will check to see if there are any upgrades from GL-Inet available by doing an HTTPS request to https://fw.gl-inet.com/firmware/<model_name>/release/list-sha256.txt.
For the Slate AX device, this looks as such:
# https://fw.gl-inet.com/firmware/axt1800/release/list-sha256.txt
4.6.11 openwrt-axt1800-4.6.11-1216-1734278520.tar fc9bf38d930e7281287b89525dda4c790be093e7adaba3b44316ed2e73150b98 47063920
4.6.8 openwrt-axt1800-4.6.8-1017-1729172935.tar eb11db2e26490e70ec3a9908a11880b104f043a28f84c9973039a85713ca7eae 46900718
4.6.4 openwrt-axt1800-4.6.4-0905-1725497901.tar f5912ed8f1add984cc1a6226f43fd52402821216ee36536313ae61f798a6e810 47077372
4.6.2 openwrt-axt1800-4.6.2-0709-1720529672.tar a3766797f96c0982bb0f9673be02f9cac640524d2e737019bf6c7865d7c37d9a 46965331
4.5.16 openwrt-axt1800-4.5.16-0321-1711033518.tar 96d2631ec6f271949c1ac179ff972fb5f77c0e0b2a2f910709134114d7d2fdcf 48816496
4.5.0 openwrt-axt1800-4.5.0-0123-1706015685.tar dd59b3e6b4e8e5b5bdf56266152ea847433bb11a60dbced77c68780610b37105 47507619
4.4.6 openwrt-axt1800-4.4.6-0908-1694157838.tar 32e32e90a68003b722d23b6955cb2a678445d188f47a5de926860e3e3f080487 59404146
4.2.3 openwrt-axt1800-4.2.3-0706-1688630948.tar 4911ff9688ba170cb8f3d6d0d16d869bae857581820fbf9bcbb9c5ba02119569 59373801
4.2.1 openwrt-axt1800-4.2.1-0414-1681482936.tar 4d50428028b63b35dbc039d0069c56a57ec8747380e9ae9cc4cd57bfa874c7a4 59373123
4.1.0 openwrt-axt1800-4.1.0-1116-1668588068.tar d152cddffee821355613ba6a0db074d9b686f128e7ef6a5d65a1952e1942b655 51961046
4.0.3 openwrt-axt1800-4.0.3-0831.tar 95371806941e6b6eecfc447db41414e741b70c217027ca129f752853ab9d4b32 49592938
Assuming that there is an entry in the above list that has version number greater than our device’s version (i.e. the first column), then we continue down the upgrade process, which is mainly handled by the usr/lib/oui-httpd/rpc/upgrade and /usr/bin/one_click_upgrade scripts. Still within the /usr/lib/oui-httpd/rpc/upgrade lua script, various sanitation is performed on the above fields to prevent command injection and also to verify the upgrade size. The router then grabs the https://fw.gl-inet.com/firmware/<model>/release/metadata_<version> URL to gather the metadata that is displayed to the user so that they can make the decision whether or not to actually upgrade. An example of the URL and response looks as such:
https://fw.gl-inet.com/firmware/axt1800/release/metadata_4.6.11
{ "metadata_version": "1.1", "compat_version": "1.0", "supported_devices":["glinet,axt1800"],
"version": { "release": "4.6.11", "date": "20241215232632", "dist": "OpenWrt", "version": "21.02-SNAPSHOT",
"firmware_type": "release2", "revision": "r16399+173-c67509efd7", "target": "ipq807x/ipq60xx", "board": "glinet_axt1800" },
"upgrade_control":"", "release_note":"# V4.6.11\r\n\r\n## Overview\r\nThis version mainly fixes some known bugs.\r\n\r\n##
Synchronized Updated Model\r\nSlate AX (GL-AXT1800).\r\n\r\n## Bug Fixes\r\n* Fixed the issue of abnormal transmit power in some cases.\r\n*
Fixed the problem of abnormal display of channel list in some cases.\r", "release_note_cn":"" }
After gathering the metadata, the upgrade lua script then invokes /usr/bin/one_click_upgrade as such:
local cmd = (string.format)("/usr/bin/one_click_upgrade \'%s\' \'%s\' \'%s\' \'%s\' \'%s\' \'%s\' \'%d\' &", firmware_url, sha256, keep_config and "1" or "0", keep_package and "1" or "0", use_mirror_dl and "1" or "0", id or "", cloud_size or Unknown_Type_Error)
It’s worth noting that the firmware_url field is generated by appending our firmware URL with the upgrade file name selected from the list-sha256.txt information, so an example of the firmware filename that gets downloaded will look something like https://fw.gl-inet.com/firmware/a1300/release/openwrt-a1300-4.4.6-0908-1694153586.tar. Continuing on into the one_click_upgrade script we can see where the device actually downloads the firmware:
if [ "$use_mirror_dl" = 1 ]; then
/usr/bin/mirror_downloader $firmware_path
while [ "$firmware_sha256sum" != "$(sha256sum /tmp/firmware.img |awk '{print $1}')" ]; do
/usr/bin/mirror_downloader $firmware_path
sleep 5
done
else
firmware_name=$(basename "$firmware_path")
curl -C - -Ls --connect-timeout 5 $firmware_path -o /tmp/firmware.img >> /dev/null // [1]
fi
As displayed at [1], there’s not really anything out of the ordinary. Instead, we show this line to contrast with how the /usr/lib/oui-httpd/rpc/upgrade lua script grabs the list-sha256.txt and metadata_<version> files with the fetch_firmware_info function:
local fetch_firmware_info = function(url)
-- function num : 0_4 , upvalues : http
local httpc = (http.new)()
httpc:set_timeout(Unknown_Type_Error)
local res, err = httpc:request_uri(url, {ssl_verify = false}) // [2]
if not res then
return nil, err
end
httpc:close()
if res.status ~= Unknown_Type_Error then
return nil, "status: " .. res.status
end
local body = res.body
if not body then
return nil, "no response data"
end
local name, sha256, size = body:match("^%S+%s+(%S+)%s+(%x+)%s+(%S+)")
if not name or not sha256 or not size then
return nil, "invalid response"
end
return name, sha256, size
end
Even though these requests are correctly made to https://* sites to prevent man-in-the-middle attacks, we clearly see at [2] that the ssl_verify option is turned off for some reason which introduces an unnecessary attack surface. Oddly, in the earliest versions of the GL-Inet code, this functionality was handled by shell scripts that correctly used curl with SSL verification turned on, but in the switch to lua, a regression was introduced. Regardless, we are left with a situation in which the firmware upgrade info can be intercepted and modified, but the actual firmware downloaded must be valid. Since there is various input checking and validation of the firmware info due to previous vulnerabilities that were discovered by other researchers in earlier versions, we are unable to immediately gain RCE via some sort of command injection.
However, there is still an option for exploitation, as we can simply trick the user into downgrading the device to a vulnerable version instead. If we modify the sha256-list.txt response such that it looks something like:
5.1.1 openwrt-axt1800-4.4.6-0908-1694157838.tar 32e32e90a68003b722d23b6955cb2a678445d188f47a5de926860e3e3f080487 59404146 // [3]
4.6.11 openwrt-axt1800-4.6.11-1216-1734278520.tar fc9bf38d930e7281287b89525dda4c790be093e7adaba3b44316ed2e73150b98 47063920
4.6.8 openwrt-axt1800-4.6.8-1017-1729172935.tar eb11db2e26490e70ec3a9908a11880b104f043a28f84c9973039a85713ca7eae 46900718
4.6.4 openwrt-axt1800-4.6.4-0905-1725497901.tar f5912ed8f1add984cc1a6226f43fd52402821216ee36536313ae61f798a6e810 47077372
4.6.2 openwrt-axt1800-4.6.2-0709-1720529672.tar a3766797f96c0982bb0f9673be02f9cac640524d2e737019bf6c7865d7c37d9a 46965331
4.5.16 openwrt-axt1800-4.5.16-0321-1711033518.tar 96d2631ec6f271949c1ac179ff972fb5f77c0e0b2a2f910709134114d7d2fdcf 48816496
4.5.0 openwrt-axt1800-4.5.0-0123-1706015685.tar dd59b3e6b4e8e5b5bdf56266152ea847433bb11a60dbced77c68780610b37105 47507619
We can add an older version of the firmware to the list but with a higher version number in the first column [5] such that the device selects a vulnerable version of the firmware (openwrt-axt1800-4.4.6-0908-1694157838.tar) for upgrading. We can also then use the available MitM attack on the metadata file it would grab (in this case https://fw.gl-inet.com/firmware/axt1800/release/metadata_5.1.1), and make the upgrade popup display completely false information, such as a newer version, release date, patch notes, etc. At no point in the upgrade process will the user be able to see that the actual firmware version they ‘upgrade’ to is actually older, at least until the user logs in after the upgrade occurs, but by that point it would be too late. For example, an attacker could force the device upgrade down to version 4.4.6, and, on the next upgrade, the attacker could utilize CVE-2023-50445 on the WAN side to execute arbitrary code in the router.
2025-08-11 - Initial Vendor Contact
2025-08-11 - Vendor Disclosure
2025-09-04 - Vendor Patch Release
2025-11-24 - Public Release
Discovered by Lilith >_> of Cisco Talos.