پرش به محتوای اصلی

ضعیف ترین پیوند لاجورد - پنج سازش کامل بین مستاجر

هکرنیوز۱۴۰۵ آبان ۸, جمعه، ساعت ۱۳:۳۶حدود 8 دقیقه مطالعه

آدرس مقاله: https://www.binarysecurity.no/posts/2026/10/one-root-case آدرس نظرات: https://news.ycombinator.com/item?id=50301854 امتیاز: 271 # نظرات: 54

من همچنین در Blue Hat Asia 2026 یک سخنرانی در مورد جزئیات این موضوع برگزار کردم و وقتی ضبط منتشر شد، پیوندی را در اینجا اضافه خواهم کرد.

اتصالات API به هر کسی اجازه می‌دهد تا به طور کامل هر اتصال دیگری را در سراسر جهان به خطر بیاندازد و دسترسی کامل به باطن متصل را می‌دهد. این شامل به خطر افتادن بین مستاجر Key Vaults و پایگاه‌های داده Azure SQL، و همچنین هر سرویس متصل خارجی، مانند Jira یا Salesforce است. تنها چیزی که مانع از بهره‌برداری می‌شود، لایه‌های اعتبارسنجی ورودی است که بر روی سیستم‌های مختلف پیچ شده است، اما همانطور که خواهید دید، گرفتن تمام موارد لبه در اینجا واقعا دشوار است.

اگر قسمت‌های اول این مجموعه را نخوانده‌اید، توصیه می‌کنم ابتدا آن‌ها را ببینید، ضعیف‌ترین پیوند لاجورد؟ - قسمت 1 و ضعیف‌ترین پیوند Azure - مصالحه کامل متقابل - مستاجر، اما اگر برایتان مهم نیست، ابتدا مهم‌ترین بخش‌های معماری را مرور می‌کنم.

از مستندات مایکروسافت، ما یک نمودار کاملا جذاب از نحوه ساخت معماری اتصال API می بینیم.

این اساسا همه چیزهایی را که برای درک نحوه عملکرد سیستم لازم است بیان می کند، آفرین به کسی که آن را ساخته است!

از این رو، می‌توانیم حدس بزنیم که اگر بتوانیم نمونه مدیریت API را فریب دهیم تا بر روی اتصالی متفاوت از اتصالات خودمان کار کند، می‌توانیم به طور مؤثر از توکن پیکربندی شده برای اتصال قربانی در سرویس پشتیبان آنها استفاده کنیم.

این سرویس در واقع می تواند هر چیزی باشد. همانطور که در اینجا می بینید، لیست خدمات باطن عملا نامحدود است و شامل تعدادی از سرویس های Azure است.

هر چقدر هم که نمودار عالی باشد، یک حذف اساسی وجود دارد که قبلا در قسمت 2 این مجموعه از آن برای تأثیرگذاری بسیار خوبی استفاده کرده ایم. با استفاده از ARM REST API DynamicInvoke یا /extensions/proxy/ نقاط پایانی، می توانیم مستقیما از طریق ARM سرویس APIM را پرس و جو کنیم. من این اختیار را گرفته ام که نمودار را برای مطابقت با آن به روز کنم.

با توجه به این موضوع و این واقعیت که ARM به عنوان یک مدیر منابع اساسا به همه چیز دسترسی کامل دارد، مسیر بهره برداری ما مشخص می شود. ما باید سرویس تماس گیرنده را فریب دهیم تا اتصالی متفاوت از اتصال ما را جستجو کند، و بنابراین کنترل کامل سرویس باطن را در اختیار بگیریم.

هشدار: البته ممکن است افرادی که این اتصالات را راه‌اندازی می‌کنند، به نشانه‌ها یا کلیدهای دسترسی خود بپردازند تا اتصال API حداقل امتیازات را در backend داشته باشد. با این حال، من حدس می زنم که این کار به ندرت انجام می شود. در مورد اتصالات OAuth، مطمئنا همیشه نشانه شخصی است که در ابتدا اتصال را برقرار کرده است. و برای مورد کلید API، خوب، چه کسی به اندازه کافی اهمیت می دهد که چنین مواردی را به حداقل برساند؟ حداقل مایکروسافت این کار را نمی کند.

اولین بهره برداری متقابل مستأجری که در اتصالات API، و در واقع در Azure به عنوان یک کل به دست آوردم، قبلا در قسمت 2 توضیح داده شده است. به عنوان خلاصه، در اینجا یک بار نمونه با استفاده از نقطه پایانی DynamicInvoke اتصال خودم برای خواندن Key Vault یک مستاجر دیگر آورده شده است.

همانطور که می بینید، این یک آسیب پذیری مسیر بسیار واضح است. این به معنای چیزی است که قبلا فرض می‌کردیم: وقتی درخواست از ARM به نمونه APIM شلیک می‌شود، بدون در نظر گرفتن اینکه روی چه چیزی کار می‌کند، حقوق همه اتصالات را دارد.

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

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

یک واقعیت کوچک جالب در مورد ARM API این است که، در برخی موارد، ممکن است آنقدر که شما تصور می کنید یک جعبه سیاه نباشد. کد مربوطه را گاهی می توان در خود انواع منابع یافت. من نمی دانم که آیا این کد واقعا روی این ماشین ها اجرا می شود یا صرفا به عنوان یک مصنوع گنجانده شده است، اما معدن طلایی از اطلاعات جالب است. بنابراین، من یک برنامه منطق استاندارد ایجاد کردم که یک میزبان کاملا اختصاصی را ارائه می دهد، SSH را در آن قرار داده و کد را استخراج می کند. ببینید چه چیزی پیدا کردم:

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

این توابع کاملا غیرمستند هستند و من هیچ مرجعی به آنها پیدا نکردم. با این حال، آنها قابل دسترسی بودند و در امتداد همان مسیر قرار داشتند. بنابراین، برای مثال، برای زدن DynamicList در اینجا، به سادگی dynamicInvoke در URI خود را به DynamicList تغییر دهید.

با دانستن اینکه اصلاح فهرست سیاه slap-dash که آنها پیاده‌سازی کردند فقط برای DynamicInvoke اعمال می‌شود، فرض کردم که اگر عملکرد یکسانی داشته باشند، همه آنها به یک شکل آسیب‌پذیر خواهند بود. بدون اینکه شما را بیش از حد با آرگومان‌های مورد نیاز و مقادیر بازگشتی در اینجا خسته کند، روش بهره‌برداری واقعا یکسان است، اگرچه بار بار کمی بیشتر درگیر است. برای DynamicList، باید هر پارامتر مسیر را به تنهایی مشخص کنید و کمی کار کنید تا به نتیجه برسید، اما همان منطق اعمال می شود.

به عنوان مثال، برای دستیابی به نوشتن متقابل مستاجر بر روی سرور SQL قربانی از طریق اتصال آنها، یک payload مانند این کار می کند:

شما به راحتی می توانید ببینید که اولین پارامترها در اینجا پیمایش مسیر را اجرا می کنند و سپس یک پرس و جو SQL دلخواه را در پایگاه داده انجام می دهند.

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

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

بارزترین تفاوت این است که برنامه های Consumption Logic، که در آن گردش کار شما با تعدادی دیگر قرار دارد، یک اتصال نسخه 1 ایجاد می کنند، در حالی که برنامه های منطق استاندارد میزبان اختصاصی یک اتصال نسخه 2 ایجاد می کنند. نمودارهای زیر تفاوت ظریف تری را بین جریان ها مشخص می کند:

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

من متوجه شدم که این باید به این معنی باشد که هر برنامه منطق مصرفی دسترسی ضمنی به هر اتصال API نسخه 1 دارد. تنها چیزی که ما را از بهره برداری از این باز می دارد باید نوعی اعتبار سنجی ورودی باشد.

نمای کلاسیک گردش کار Logic App از نظر ورودی کاملا محدود است، اما هر دو نقطه پایانی API و نمای کد در رابط کاربری گرافیکی وجود دارند که به ما امکان می‌دهند کمی بیشتر با ورودی‌ها بازی کنیم.

این به ما امکان می دهد ورودی ها را با جزئیات بیشتری ببینیم، آنها را ویرایش کنیم و حتی موارد بیشتری را اضافه کنیم. ترفند واضح تغییر کانکتور ارجاع شده به اتصال قربانی با شکست مواجه می شود، زیرا زمان اجرا اعتبار سنجی گسترده ای را انجام می دهد که شما مالک اتصال هستید. با این حال، ما پایگاه کد را داریم، بنابراین می‌توانیم سعی کنیم تمام پارامترهای معتبر را پیدا کنیم. کشف پارامتر host.api.RuntimeUrl برای من به جستجوی زیادی نیاز نداشت.

نمی‌توانم کاملا متوجه شوم که چرا این پارامتر گنجانده شده است، یا اینکه چرا تا به امروز هنوز پذیرفته شده است، اما به روشی که شما انتظار دارید کار می‌کند. پس از انجام یک سری اعتبارسنجی روی اتصال ارجاع شده در host.connection، می‌توانید مشخص کنید که به جای runtimeUrl که در آن اتصال ایجاد شده است، از چیزی کاملا متفاوت استفاده کند. تا زمانی که میزبان با azure-apihub.net خاتمه یابد، سربرگ مجوز مورد نیاز را نیز شامل می شود.

خواننده با چشم ممکن است متوجه شود که runtimeUrl مورد استفاده در اکسپلویت فقط ConnectId نیست. این به این دلیل است که برخی از عناصر اضافی به URI اضافه می شوند، اما برای ما هیچ پیامدی ندارد. اکسپلویت به خوبی کار می کند.

البته من دوباره این موضوع را به مایکروسافت گزارش دادم و آنها مدتی را صرف کار برای رفع مشکل کردند. هنگامی که در نهایت انجام شد، اکسپلویت یک پیام خطا را برگرداند:

به جز طولانی بودن بیش از حد این پیام، به نظر می رسد یک راه حل کاملا مناسب باشد. URL زمان اجرا باید دقیقا با آنچه مورد انتظار است مطابقت داشته باشد. در غیر این صورت، بدون تاس. جدای از حذف کامل پارامتر، کاملا عاقلانه است. مگر اینکه، البته، آن مقدار را در زمان اشتباه بررسی کند:

این دوباره کار می کند، با همان نتیجه. آنچه در اینجا اتفاق می‌افتد این است که اعتبارسنجی قبل از عادی‌سازی مسیر انجام می‌شود، بنابراین زمان اجرا فکر می‌کند که URI به اتصال ارجاع‌شده من اشاره می‌کند، اما نمونه APIM آن را متفاوت می‌بیند.

و درست مثل آن، یک آسیب پذیری حیاتی دیگر گرفتم.

سرگرمی به همین جا ختم نمی شود. هنگامی که مایکروسافت موفق شد راه حلی را برای پیمودن این مسیر جمع آوری کند، یک اتفاق شگفت انگیز رخ داد. مسیر اصلی RuntimeUrl دیگر تأیید نشد و در نتیجه، می‌توانید آن حمله را دوباره انجام دهید. من تعدادی عکس را اضافه می کنم، اما آنها همان عکس های بالا هستند، بنابراین می توانید آنها را تصور کنید.

در مجموع، API Connections پنج آسیب‌پذیری حیاتی افزایش امتیاز را در Azure برای من ایجاد کرده است، که شاید بیش از حد انتظار باشد. همه آسیب‌پذیری‌های گزارش‌شده در اینجا در مدت زمان معقولی پس از ارسال گزارش‌ها رفع شدند، و در حالی که برخی از اختلافات با MSRC در طول مسیر وجود داشت، در کل، من از نتایج کاملا راضی هستم.

خواندن متن کامل در هکرنیوزبه زبان اصلی، در سایت ناشر باز می‌شود
متن اصلی (انگلیسی)

Azure's Weakest Link – Five Full Cross-Tenant Compromises

Article URL: https://www.binarysecurity.no/posts/2026/10/one-root-case Comments URL: https://news.ycombinator.com/item?id=50301854 Points: 271 # Comments: 54

همه‌ی اخبار فناوری