ما حساب های ChatGPT را تصاحب کردیم
آدرس مقاله: https://www.parameter.ai/labs/we-found-a-gap-at-openai آدرس نظرات: https://news.ycombinator.com/item?id=50314699 امتیاز: 241 # نظرات: 112
با دور زدن جعبه ایمنی و خطمشی امنیت محتوا ChatGPT، تیم تحقیقاتی ما توانستند حساب هر کسی را به سادگی با ارسال یک پیوند به آنها تسخیر کنند.
در اکتبر 2026، راهی پیدا کردیم تا یک اشتراک عمومی معمولی ChatGPT را به جاوا اسکریپت کنترلشده توسط مهاجم تبدیل کنیم که در جلسه ورود به سیستم هر کسی که آن را باز میکند اجرا میشود.
یک مهاجم میتواند یک مکالمه مخرب ایجاد کند، آن را با استفاده از ویژگی اشتراکگذاری معمولی ChatGPT منتشر کند و پیوند را برای کاربر دیگری ارسال کند. وقتی قربانی اشتراکگذاری را باز کرد، بارگذاری بهصورت chatgpt.com با دسترسی به جلسه وب تأیید شده قربانی اجرا شد.
ما تأیید کردیم که این کد میتواند فهرست مکالمه قربانی را برشمرد، محتوای یک مکالمه خصوصی را که هرگز با مهاجم به اشتراک گذاشته نشده بود، بازیابی کند و دادههای آن مکالمه را به یک سرور خارجی ارسال کند. بارگذاری به تغییر صفحه یا نمایش یک هشدار محدود نمیشد، بلکه میتوانست مستقیما APIهای تأیید شده ChatGPT را به عنوان قربانی فراخوانی کند و اساسا به ما امکان میدهد حساب ChatGPT قربانی را در اختیار بگیریم.
قربانی نیازی به نصب برنامه، پیوستن به پروژه، چسباندن کد، یا باز کردن ابزارهای توسعه دهنده نداشت. باز کردن پیوند مشترک تنها اقدام مورد نیاز بود.
OpenAI این مشکل را در 26 اکتبر برطرف کرد و گزارش را به عنوان P1 طبقه بندی کرد.
این زنجیره با دو ویژگی شروع شد که به خودی خود بی ضرر به نظر می رسیدند: یک نمودار و یک پیش نمایش HTML.
سؤالی که این تحقیق را آغاز کرد ساده بود: اگر کد پیشنمایش در یک وبسایت متفاوت قرار میگرفت، هنوز با چه چیزی صحبت میکرد؟
ChatGPT میتواند یک بلوک کد HTML را با استفاده از ویژگی پیشنمایش به یک صفحه وب کوچک تبدیل کند. از آنجایی که آن صفحه ممکن است حاوی کد دلخواه باشد، ChatGPT به طور معقولی آن را در یک قاب محدود در یک آدرس وب دیگر اجرا می کند. پیشنمایش میتواند جاوا اسکریپت را اجرا کند، اما مرورگر آن را بهعنوان یک وبسایت متفاوت در نظر میگیرد، بنابراین نمیتواند مستقیما صفحه ChatGPT وارد شده در اطراف آن را بررسی کند.
در ابتدا به نظر می رسید که این انزوا دقیقا همانطور که در نظر گرفته شده است کار می کند. کد داخل پیشنمایش نمیتواند parent.document را بخواند، که صفحه اصلی ChatGPT است. این باید پایان کار بود.
مکالمه همچنین حاوی یک نمودار عادی تعاملی بود. در پشت صحنه، نمودار یک کتابخانه ریاضی به نام MathLive را بارگذاری کرد. بارگیری آن بیشتر از ترسیم نمودار انجام داد: همچنین یک شنونده در صفحه اصلی ChatGPT برای پیام های مربوط به صفحه کلید روی صفحه MathLive نصب کرد.
مرورگرها API مربوطه را postMessage می نامند. این یک راه قانونی برای تبادل اطلاعات دو فریم است حتی زمانی که مرورگر از خواندن صفحات یکدیگر جلوگیری می کند. می توانید آن را به عنوان یک اسلات ایمیل در نظر بگیرید: پیش نمایش محدود شده نمی تواند وارد صفحه اصلی شود، اما همچنان می تواند پیامی را از طریق شکاف ارسال کند.
این فقط در صورتی امن است که گیرنده پیام را چک کند که چه کسی پیام را ارسال کرده است.
MathLive آن تنظیماتی را که ما به آن علاقه مند بودیم بررسی نکرد. شنونده آن پیامی را پذیرفت که طرحبندی صفحهکلید مجازی را تغییر میداد، و این طرحبندی مجاز بود حاوی HTML باشد. نمودار گیرنده را نصب کرده بود. پیش نمایش یک فرستنده نامعتبر به ما داد. دو ویژگی نامرتبط به طور تصادفی یک مسیر در ماسهبازی ایجاد کرده بودند.
پیش نمایش دو پیام ارسال کرد. اولی یک طرحبندی صفحهکلید مجازی را با HTML ما جایگزین کرد. دومی به MathLive گفت که صفحهکلید را نشان دهد و باعث شد که طرحبندی جدید را ارائه کند:
MathLive نوع پیام عمومی را تشخیص داد، اما کنترلکننده سطح بالای آن از خطمشی مبدأ هیچکدام استفاده میکرد، به این معنی که پیامها را از هر آدرس وب میپذیرفت. همچنین نیازی به ارسال پیام تنظیمات به روز رسانی از یک پنجره تأیید شده قبلی نداشت. هر کسی که می توانست به شنونده برسد و قالب پیام را می دانست می توانست طرح بندی را جایگزین کند.
هنگامی که صفحه کلید باز شد، MathLive طرح ارائه شده را به یک رشته HTML پیوست و آن را به innerHTML در صفحه واقعی ChatGPT اختصاص داد. کمکی به نام createHTML در ابتدا به نظر می رسید که ممکن است مقدار را پاکسازی کند. نشد؛ رشته را به عنوان قابل اعتماد علامت گذاری کرد و HTML ما را بدون تغییر ارسال کرد.
این هیجان انگیز بود، اما ما هنوز اجرای جاوا اسکریپت را نداشتیم. تگ های اسکریپتی که از طریق innerHTML درج می شوند به طور خودکار اجرا نمی شوند.
مرحله بعدی یک iframe با استفاده از srcdoc بود، یک ویژگی مرورگر که به فریم تعبیه شده اجازه می دهد HTML خود را مستقیما در یک ویژگی حمل کند:
MathLive این فریم را در سند اصلی ChatGPT بدون ویژگی sandbox قرار داد. که به ما دو خاصیت مفید داد. ابتدا srcdoc یک سند تازه ایجاد کرد که در آن یک اسکریپت خارجی می توانست اجرا شود. دوم، چون صفحه اصلی ChatGPT فریم را ایجاد کرده است، مرورگر به آن هویت وب https://chatgpt.com داد. بنابراین کدهای داخل فریم جدید می توانند به صفحه والد دسترسی داشته باشند.
سیاست امنیتی محتوای ChatGPT یا CSP، دوباره ما را متوقف کرد. CSP کنترل میکند کدام اسکریپتها ممکن است یک صفحه بارگیری شوند، و این خطمشی به درستی جاوا اسکریپت درون خطی را مسدود کرده است. با این حال، اسکریپتها را از YouTube مجاز کرد.
نقطه پایانی oEmbed YouTube از یک پارامتر پاسخ به تماس به سبک JSONP پشتیبانی می کند. پاسخهای JSONP به جای JSON معمولی، جاوا اسکریپت هستند. نقطه پایانی سعی کرد یک تماس برگشتی نامعتبر را رد کند، اما قبل از بازگشت خطای اعتبارسنجی، آن را در پاسخ قرار داد:
پایان دادن به تماس ما با ;void باعث شد شیء اضافه شده توسط YouTube بی ضرر شود. از آنجایی که YouTube قبلا توسط CSP ChatGPT مجاز بود، مرورگر این پاسخ را به عنوان یک اسکریپت بارگیری کرد و پاسخ تماس ما را در قاب جدید اجرا کرد.
ما اکنون جاوا اسکریپت دلخواه داشتیم که به عنوان chatgpt.com اجرا می شد. پیشنمایش اصلی هنوز در آدرس وب جداگانهاش مجزا بود. ما با متقاعد کردن یک مؤلفه قابل اعتماد در صفحه اصلی برای ایجاد یک سند جدید و بدون جعبه ایمنی برای ما از مرز عبور کرده بودیم.
تا اینجای کار، این یک فرار مفید از سندباکس بود، اما اولین نسخه کارآمد یک حمله در دنیای واقعی متقاعدکننده نبود. این برنامه از یک برنامه ChatGPT کنترل شده توسط محقق به عنوان فرستنده استفاده کرد. قربانی باید ابتدا آن برنامه را متصل یا فراخوانی کند.
ما در مرحله بعد سعی کردیم بار را از طریق یک پیوست HTML بومی تحویل دهیم. ChatGPT پیوست را در همان پیشنمایش جعبه ایمنی باز کرد تا بتواند پیامهای مخرب MathLive را ارسال کند.
با این حال، وقتی مکالمه را به عنوان یک اشتراک عمومی صادر کردیم، پیوست باقی ماند اما نمودار قبلی اینطور نبود. این نمودار ضروری بود زیرا MathLive را بارگیری می کرد و شنونده پیام آسیب پذیر را در صفحه اصلی نصب می کرد. بدون آن، پیوست همچنان میتوانست پیامها را ارسال کند، اما چیزی به آنها گوش نمیداد یا پردازش نمیکرد.
موفقیت این بود که هر دو قطعه را مستقیما در یک گفتگوی عمومی معمولی قرار داد:
پیوند /share/<id> حاصل، زنجیره کامل را برای کاربر دیگری حفظ کرد. مهاجم میتواند آن را به همان روشی که هر مکالمه مشترک ChatGPT را ارسال میکند، از طریق ایمیل، چت، یک بلیط پشتیبانی یا یک پست اجتماعی ارسال کند. قربانی نیازی به نصب چیزی، پیوستن به فضای کاری مهاجم، یا احراز هویت از طریق جریان کنترل شده توسط مهاجم نداشت. آنها فقط باید از URL مشترک ChatGPT مهاجم بازدید می کردند.
ما دو نسخه از تعامل را مشاهده کردیم. در پایدارترین بازتولید، قربانی اشتراکگذاری را باز کرد و یک بار روی دکمه Preview معمولی ChatGPT کلیک کرد. بعدا بلوک HTML را بهعنوان قابل پیشنمایش علامتگذاری کردیم تا ChatGPT آن را بهطور خودکار باز کند. در آن نسخه، باز کردن پیوند تنها کلیک قربانی بود. ما مسیر خودکار را سه بار در یک حساب جداگانه بازتولید کردیم، از جمله پس از یک بازخوانی سخت، با هشدار پس از تقریبا 4.5 ثانیه ظاهر شد.
نمودار و پیشنمایش بهطور مستقل بارگیری میشوند، بنابراین محموله میتواند گاهی پیام خود را قبل از آماده شدن MathLive ارسال کند. حامل نهایی آن مسابقه را با امتحان مجدد همان دو پیام برای مدت محدودی انجام داد. یک نگهبان در صفحه اصلی اطمینان حاصل کرد که اثبات مکالمه خصوصی و درخواست خروجی فقط یک بار اجرا می شود.
در این مرحله، اشتراک عمومی میتواند هشداری را نشان دهد که مرورگر آن را از chatgpt.com شناسایی کرده و میتواند یک بنر به صفحه اصلی اضافه کند. این ثابت کرد که کد ما در کجا اجرا می شود. هنوز نشان نداد که چرا این اشکال اهمیت دارد.
در این مرحله، نمایش یک هشدار کمترین جالب ترین کاری بود که این اکسپلویت می توانست انجام دهد. جاوا اسکریپت بهعنوان chatgpt.com اجرا میشد، به این معنی که میتوانست با ChatGPT با استفاده از زمینه احراز هویت شده مشابه برنامه وب معمولی تعامل داشته باشد.
محموله اطلاعات جلسه از قبل در دسترس صفحه را خواند و از آن برای فراخوانی APIهای مکالمه ChatGPT استفاده کرد. ابتدا صحبت های اخیر قربانی را برشمرده است. سپس می تواند داده های پیام را برای یک مکالمه خصوصی انتخاب شده درخواست کند:
این دسترسی مستقیم به API تأیید شده بود، نه خراش دادن متنی که اتفاقا روی صفحه قابل مشاهده بود. مکالمه مورد نظر با اشتراک مخرب ارتباطی نداشت و هرگز با مهاجم به اشتراک گذاشته نشده بود.
هنگامی که پاسخ برای جاوا اسکریپت تزریق شده در دسترس بود، ارسال داده ها خارج از سایت ساده بود. بارگذاری یک درخواست تصویر معمولی به سروری که ما کنترل میکردیم ایجاد کرد.
ما عمدا فقط بخش کوچکی از پاسخ را به خارج از سایت ارسال کردیم. کد تزریق شده قبلا پاسخ مکالمه تأیید شده را دریافت کرده بود و می توانست محتوای آن را بخواند، بنابراین آسیب پذیری به آن مقدار محدود نمی شد.
نتیجه، یک ابزار بدوی عملی برای سرقت اطلاعات بین کاربر بود. یک مکالمه عمومی مخرب می تواند در جلسه ChatGPT وارد شده کاربر دیگر اجرا شود، مکالمات خصوصی را برشمرد، محتوای پیام خصوصی را بازیابی کند و داده های انتخاب شده را به سروری که توسط مهاجم کنترل می شود ارسال کند.
از آنجا که کد با دسترسی تأیید شده برنامه وب اجرا می شد، دسترسی آن ذاتا محدود به نقاط پایانی مکالمه مورد استفاده در اثبات ما نبود. سایر دادهها و اقداماتی که از طریق APIهای frontend تأیید شده ChatGPT در معرض دید قرار میگیرند در همان مرز امنیتی قرار داشتند. اساسا، ما میتوانیم هر اقدامی را از طرف حساب ChatGPT قربانی انجام دهیم.
خود سندباکس پیش نمایش کار کرد. کد داخل پیشنمایش نمیتواند مستقیما صفحه ChatGPT را بخواند. مشکل این بود که یکی دیگر از اجزای صفحه اصلی مایل به پذیرش دستورالعمل های آن بود.
سه تصمیم طراحی این اشتباه را به یک بهره برداری کامل تبدیل کرد:
پاسخ YouTube راهحل نهایی برای CSP بود، نه علت اصلی. مسدود کردن تنها آن نقطه پایانی میتواند یک مسیر به جاوا اسکریپت را حذف کند و در عین حال یک پیشنمایش نامعتبر باقی بماند که بتواند HTML را در ChatGPT وارد کند.
OpenAI هم اجرای جاوا اسکریپت و هم اثبات مکالمه خصوصی را بازتولید کرد. این اصلاح در دو نسخه از وب ظاهری ChatGPT ارائه شد. در طول عرضه، تغییرات CSP بخشی از زنجیره اصلی را مسدود کرد در حالی که یک نسخه هنوز به بهروزرسانی نیاز داشت. در 26 اکتبر، OpenAI تأیید کرد که هر دو نسخه اکنون پیامهای متقابل MathLive را که توسط گزارش استفاده میشد رد کرده و مشکل را حل شده علامتگذاری کردند.
این اشکال جالب بود زیرا هر ویژگی فردی معقول به نظر می رسید. پیش نمایش جدا شد. نمودارها می توانند صفحه کلید ریاضی را بارگیری کنند. فریم ها می توانند پیام ها را رد و بدل کنند. CSP به یک ارائه دهنده رسانه بزرگ اجازه داد. مکالمات عمومی می تواند به اشتراک گذاشته شود. این آسیبپذیری تنها زمانی ظاهر شد که همه آن ویژگیها در یک صفحه ترکیب شدند.
داستان اصلی بالا شامل زنجیره کامل اکسپلویت است. جزئیات زیر برای خوانندگانی گنجانده شده است که می خواهند کد تولید و تغییرات محموله را با دقت بیشتری دنبال کنند.
جریان کنترل حذف شده مربوطه معادل با:
نرمالسازی طرحبندی، طرحبندیها[].لایهها[].نشانهگذاری حفظ شد. نمایش صفحه کلید در نهایت معادل با:
createHTML بهعنوان یک هویت یا پوششهای Trusted Types عمل میکند، نه یک ضدعفونیکننده. Trusted Types میتواند افرادی را که به یک سینک HTML اختصاص میدهد محدود کند، اما یک خطمشی هویت یک رشته کنترلشده توسط مهاجم را ایمن نمیکند.
تجزیه کننده و انتقال CSP. عملیات innerHTML میتواند یک iframe ایجاد کند، اما اسکریپتی که مستقیما به این روش درج شود بیحرکت میماند. srcdoc بدون جعبه ایمنی باعث تجزیه سند HTML جدید شد و مبدا ChatGPT جاسازی شده را به ارث برد. آن سند همچنین CSP مؤثری را که در طول آزمایش ضبط شده بود، به ارث برد، که کدهای درون خطی را مسدود کرد اما www.youtube.com را در script-src-elem مجاز کرد.
پاسخ oEmbed HTTP 200 را با Content-Type: text/javascript برگرداند. charset=UTF-8 و X-Content-Type-Options: nosniff ; هیچ سرصفحه Cross-Origin-Resource-Policy مشاهده نشد. Google براکتهای زاویهای را در تماس برگشتی بازنویسی کرد، بنابراین payload از دستور تابع کلاسیک به جای توابع پیکان استفاده کرد. پایان دادن به برنامه با ;void شی خطای اضافه شده توسط نقطه پایانی را مصرف می کند.
برای اثبات مکالمه خصوصی، تابع با toString() به منبع تبدیل شد، نقلقولهای دوتایی به نقلقولهای تکی تبدیل شدند و فضای خالی جمع شد. URLSearchParams سپس آن را در callback کدگذاری کرد، URL اسکریپت در داخل <script src> HTML-escape شد و کل آن عنصر دوباره در ویژگی srcdoc iframe فرار کرد. تماس نهایی 5533 کاراکتر بود. URL یوتیوب 7309 کاراکتر بود. عنصر اسکریپت 7337 کاراکتر بود. و نشانه گذاری نهایی iframe 7390 کاراکتر بود.
احراز هویت خوانده شده است. فریم با مبدأ یکسان، #client-bootstrap را از سند والد تجزیه کرد، نشانه دسترسی جلسه و شناسه حساب را استخراج کرد، و شناسه حساب موجود در توکن را ملزم کرد که با جلسه زمانی که هر دو حضور داشتند موافقت کند. از این هدرهای درون حافظه استفاده کرد:
فقط یک 403، 404 یا 405 در درخواست جزئیات باعث شد که کد مسیر قدیمی /backend-api/conversation/<id>?include_full_conversation=true را امتحان کند. اعتبارسنجی فقط یک مقدار کوچک انتخاب شده از پاسخ ارسال کرد. قبل از درخواست تصویر خارجی، ارجاعات به نشانه، حساب، بوت استرپ، جلسه و هدر درخواست را پاک می کرد.
درس گسترده تر این است که مرزهای امنیتی باید در سراسر محصول کامل باشد، نه فقط در داخل اجزای منفرد. هر سطح عمومی یا قابل اشتراکگذاری باید بهعنوان ورودی کنترلشده توسط مهاجم تلقی شود، هر پیام متقابل فریم باید احراز هویت شود، و نشانهگذاری غیرقابل اعتماد باید در کل مسیر رندر آن در جعبه ایمنی باقی بماند.
متن اصلی (انگلیسی)
We Took over ChatGPT Accounts
Article URL: https://www.parameter.ai/labs/we-found-a-gap-at-openai Comments URL: https://news.ycombinator.com/item?id=50314699 Points: 241 # Comments: 112