۲۲ سپتامبر ۲۰۲۶، محققان ThreatDown از باتنت CARBONATO رونمایی کردند. این باتنت به سرورها از طریق API باز Docker بدون رمز عبور وارد میشود، یک عامل هوش مصنوعی را روی هاست راهاندازی میکند و ابتدا به دنبال کلیدهای مدلهای زبانی میگردد. کلیدهای SSH و توکنهای دسترسی بعد از آن میآیند. اگر روی VPS شما پارسرهایی در کانتینرها در حال اجرا هستند و در .env کلیدهای OpenRouter یا OpenAI و نامهای کاربری پروکسی وجود دارد، این پروفایل ریسک شماست. در زیر تجزیه و تحلیلی از نحوه حمله و یک چکلیست ۱۵ دقیقهای که این ورودی را میبندد، ارائه شده است.
چه چیزی پیدا شد: ۴.۳ گیگابایت تصویر و عاملی به نام GH0ST
همه چیز با یک مخزن Docker غیرقابل دسترسی از سوی خود اپراتورها آغاز شد. به گفته ThreatDown، در آن ۵۹ مخزن، ۲۳۴ برچسب تصویر و ۴.۳ گیگابایت داده وجود داشت. این آرشیو دورهای از اکتبر ۲۰۲۴ تا اوت ۲۰۲۶ را پوشش میدهد، به این معنی که باتنت تقریباً به مدت دو سال فعالیت کرده است قبل از اینکه توصیف شود. در مخازن، ماینر XMRig و تصاویری با نامهای مانند fsociety/agent پیدا شد.
زنجیره عفونت طبق گزارش به این صورت است:
- اسکنر به دنبال هاستهایی میگردد که Docker API بر روی TCP ۲۳۷۵ بدون احراز هویت باز است.
- از طریق این API، کرم یک کانتینر با امتیاز بالا را با سیستم فایل هاست راهاندازی میکند. از این لحظه به بعد، او عملاً ریشه (root) در ماشین است.
- یک تونل SSH معکوس به زیرساخت اپراتورها راهاندازی میشود و یک سرور SSH با کلید آنها نصب میشود.
- تثبیت از طریق cron، تایمرهای systemd، rc.local و OpenRC انجام میشود و فایلها به عنوان غیرقابل تغییر علامتگذاری میشوند. فرآیندهای نظارتی دوباره تصاویر را دانلود میکنند اگر چیزی حذف شود.
- کانتینر به عنوان
systemd-resolvedپنهان میشود و فرآیند به عنوان جریان هسته[kworker/u2:0]عمل میکند. - هر پنج دقیقه، اسکریپتها زیرشبکههای همسایه /۲۴ و پلهای Docker را برای پیدا کردن پورت باز ۲۳۷۵ اسکن میکنند.
گسترش به طور کامل خودکار است و به هوش مصنوعی وابسته نیست. هوش مصنوعی در اینجا مسئول آنچه در داخل سرور تصرف شده اتفاق میافتد، است.
چرا باتنت به عامل هوش مصنوعی نیاز دارد و چرا به کلیدهای LLM نیازمند است
یک فریمورک باز Hermes Agent با شخصیت GH0ST روی هاست نصب میشود (دستورالعملهای آن در فایل SOUL.md قرار دارد). اپراتور وظیفهای را در تلگرام مینویسد، و عامل آن را به همراه دستورالعملها به دروازه LLM عملیات ارسال میکند. مدل وظیفه را تجزیه و تحلیل میکند، دستورات را برای ترمینال مینویسد، خروجی را میخواند و تصمیم میگیرد که چه کار کند. نتایج به تلگرام بازمیگردند.
در دستورالعملهای عامل، اولویتها به وضوح نوشته شده است. ThreatDown نقل قول میکند: «کلیدهای API هوش مصنوعی اولویت مطلق هستند. ابتدا استخراج کنید». در لیست ۱۴ ارائهدهنده مدل، از جمله OpenAI، Anthropic، Google، Groq، Mistral و OpenRouter وجود دارد. حسابهای SSH، توکنهای دسترسی و دادههای پایگاهها در نقاط بعدی قرار دارند.
منطق ساده است: کلید دزدیده شده LLM به سرعت به محاسبات رایگان یا کالایی برای فروش مجدد تبدیل میشود و هزینه آن را صاحب کلید پرداخت میکند. بر خلاف ماینینگ، این نوع سرقت در بار پردازنده قابل مشاهده نیست. تنها زمانی متوجه آن خواهید شد که صورتحسابی از ارائهدهنده مدل دریافت کنید.
چرا این موضوع به کسانی که پارس میکنند مربوط میشود
استک معمولی پارس در سال ۲۰۲۶ به این صورت است: VPS، چندین کانتینر (کرالر، صف، پایگاه، مرورگر بدون رابط کاربری)، LLM برای تجزیه صفحات و مجموعهای از پروکسیها. تمام اسرار در یک .env یا در متغیرهای محیطی کانتینرها قرار دارد. برای عاملی که «همه چیز را به طور تصادفی میخواند» با دسترسی ریشه، این یک طعمه آماده در یک فایل است:
- کلیدهای LLM: به خاطر آنها CARBONATO ایجاد شده است؛
- نامهای کاربری و رمزهای عبور پروکسی: گزارش به طور جداگانه آنها را مشخص نمیکند، اما عامل با دسترسی ریشه هر حساب و توکنی را که میبیند جمعآوری میکند و معمولاً اعتبارهای پروکسی در کنار هم قرار دارند؛
- کلیدهای ابری و دسترسی به پایگاهها با نتایج پارس؛
- خود سرور: XMRig در همان آرشیو به این معنی است که CPU کرالر شما به ماینینگ اختصاص مییابد و وظایف به دلیل زمانهای تایماوت از بین میروند.
مشکل جداگانهای با شهرت وجود دارد. سروری که کرم از آن به اسکن زیرشبکههای دیگر میپردازد، به سرعت در لیستهای سوءاستفاده قرار میگیرد و هاست میتواند آن را به دلیل شکایت مسدود کند. برای پارس، این یک ضربه دوگانه است: IP سرور علامتگذاری شده است و اعتبارهای پروکسی دزدیده شده در حال حاضر ترافیک شما را با درخواستهای دیگران مصرف میکنند.
چگونه پورت ۲۳۷۵ باز میشود، در حالی که شما آن را باز نکردهاید
به طور پیشفرض، Docker به ساکت UNIX محلی گوش میدهد، نه به شبکه. پورت ۲۳۷۵ زمانی ظاهر میشود که کسی به عمد -H tcp://0.0.0.0:2375 را به پیکربندی دیمون اضافه کرده باشد. معمولاً این کار برای اتصال به IDE از راه دور، CI یا پنل مدیریت کانتینرها انجام میشود و سپس فراموش میشود. مستندات Docker به وضوح هشدار میدهد که دسترسی به دیمون معادل دسترسی ریشه به ماشین است و توصیه میکند که کلیدها را مانند رمز عبور ریشه نگهدارید. نسخه رمزگذاری شده با TLS بر روی پورت ۲۳۷۶ کار میکند، در حالی که ۲۳۷۵ به معنای متن باز بدون تأیید مشتری است.
دامنه دوم به کسانی ضربه میزند که مطمئن هستند «من که ufw دارم». در مستندات Docker گفته شده است که ترافیک پورتهای منتشر شده کانتینرها در جدول nat قبل از زنجیرههای INPUT و OUTPUT که ufw به آنها تکیه میکند، هدایت میشود. در عمل، قوانین ufw برای چنین پورتهایی به سادگی کار نمیکند. اگر شما Redis، پنل صف یا مدیر پروکسی را با -p 6379:6379 راهاندازی کردهاید، پورت به اینترنت درز میکند، هرچه هم که ufw status نشان دهد.
چکلیست ۱۵ دقیقهای برای سرورهای با پارسرها
۱. بررسی کنید که Docker API به شبکه گوش نمیدهد
- پورتهای شنود را بررسی کنید:
ss -tlnp | grep -E '2375|2376|dockerd'. اگر در خروجی0.0.0.0:2375یا:::2375وجود دارد، فوراً آن را ببندید. - بررسی کنید که پرچم از کجا آمده است:
/etc/docker/daemon.json(کلید"hosts") و واحدsystemctl cat docker(خطExecStartبا-H tcp://). - شنونده TCP را حذف کنید و دیمون را دوباره راهاندازی کنید. برای مدیریت از راه دور از زمینه SSH استفاده کنید:
docker context create remote --docker host=ssh://user@server. در این صورت، پورت به طور کلی نیازی به وجود ندارد. - اگر TCP به هر حال ضروری است (CI، ارکستراتور)، فقط ۲۳۷۶ با احراز هویت متقابل TLS و لیست سفید IP منبع استفاده کنید.
۲. بررسی کنید که چه چیزی از کانتینرها به بیرون درز میکند
- اجرا کنید
docker ps --format '{{.Names}} {{.Ports}}'. هر چیزی که با0.0.0.0:شروع میشود، از اینترنت به دور از ufw در دسترس است. - خدمات کاربردی (Redis، Postgres، Mongo، پنلهای صف، Selenium Grid، API مدیر پروکسی) را فقط بر روی آدرس محلی منتشر کنید:
-p 127.0.0.1:6379:6379. دسترسی خارجی را از طریق تونل SSH انجام دهید. - اگر بدون پورت خارجی نمیتوان گذشت، در زنجیره
DOCKER-USERفیلتر کنید: Docker آن را دوبارهنویسی نمیکند و دقیقاً به ترافیک کانتینرها اعمال میشود. - روی سرور پروکسی باز بدون احراز هویت (Squid بر روی ۳۱۲۸، SOCKS بر روی ۱۰۸۰ «برای خودیها») نداشته باشید. اسکنرها به طور مرتب چنین پورتهایی را پیدا میکنند و از طریق IP شما ترافیک خارجی با شکایات دیگران عبور میکند.
۳. با اسرار کنار بیایید
- کلیدها را جدا کنید: یک کلید LLM جدا برای هر سرور یا پروژه، با محدودیت هزینه از ارائهدهنده مدل. کلید دزدیده شده با محدودیت ۲۰ دلار — مشکل است، بدون محدودیت — حفرهای در بودجه.
- کلیدهای پروکسی را نیز بر اساس وظایف تقسیم کنید: یک نام کاربری جداگانه (زیرحساب) برای هر پارسر. در این صورت، نشت را میتوان بر اساس مصرف نام کاربری خاص مشاهده کرد و میتوان فقط آن را لغو کرد، بدون اینکه کار باقیمانده متوقف شود.
- تمام
.envرا از طریقenv_fileبه کانتینر ندهید، اگر سرویس به دو کلید از بیست نیاز دارد. - جایی که ممکن است، دسترسی را به IP سرور متصل کنید: لیست سفید در ارائهدهنده پروکسی یا محدودیت کلید API بر اساس آدرس.
در مورد اینکه کجا و چگونه نامهای کاربری پروکسی را در اسکریپتها و کانتینرها ذخیره کنید، ما در تجزیه و تحلیلی درباره ذخیرهسازی امن اعتبارنامههای پروکسی نوشتهایم.
۴. امتیازات اضافی را حذف کنید
- کانتینرها را با
--privilegedراهاندازی نکنید و/یا/var/run/docker.sockرا بدون نیاز شدید به داخل نزنید. سوکت درون کانتینر معادل ریشه (root) در هاست است. - برای مرورگرهای بدون رابط کاربری معمولاً
--shm-sizeو پروفایل seccomp کافی است. حالت امتیازی «برای اینکه Chrome راه بیفتد» یک سازش بد است.
چگونه بفهمید که شما قبلاً آلوده شدهاید
ThreatDown و تجزیه و تحلیلهای گزارش آن نشانههای زیر را برای نفوذ ارائه میدهند:
- فایل
SOUL.mdبا کلمه GH0ST (به عنوان مثال،/root/.hermes/SOUL.md); - متغیر محیطی یا خطی در
.env:CARBONATO_API_KEY; - فایلهای
/usr/local/bin/.docker-network-monitorو/usr/sbin/systemd-logindمشکوک; - کانتینری با نام
systemd-resolved(systemd-resolved واقعی — سرویس هاست است، نه کانتینر); - ترافیک خروجی غیرمنتظره به API تلگرام و تونلهای SSH معکوس به سمت AS262145;
- اتصالات به آدرسهای ۴۵.۷۹.۱۸۳.۶۱، ۲۱۳.۱۳۶.۷۹.۱۱۵، ۱۹۰.۲۱۱.۱۲۴.۱۸۷;
- فایلهای غیرقابل تغییر در cron و systemd:
lsattr /etc/cron.d/* /etc/systemd/system/*پرچمiرا نشان میدهد.
اگر حتی یک نشانه مطابقت داشت، پاکسازی سرور به صورت دستی بیفایده است: تثبیت چندلایه است و نگهبان ایمپلنتها را بازمیگرداند. ترتیب صحیح به این صورت است:
- از ماشین دیگری تمام کلیدهایی را که در سرور بودهاند، لغو کنید: LLM، ابر، پایگاهها، پروکسی.
- مصرف هر کلید را در هفتههای اخیر از ارائهدهندگان بررسی کنید. آمار مربوط به نام کاربری پروکسی به سرعت ترافیک خارجی را نشان میدهد.
- یک سرور جدید از تصویر خالص راهاندازی کنید، کلیدهای جدید صادر کنید و فقط سپس دادهها را منتقل کنید، بدون باینریها و فایلهای cron از ماشین قدیمی.
پروکسیها در اینجا چه نقشی دارند و چه مشکلاتی را حل نمیکنند
پروکسیها سرور را از CARBONATO محافظت نمیکنند. کرم از طریق درخواستهای خروجی شما نمیآید، بلکه از طریق پورت ورودی وارد میشود. اما یک طرح کار صحیح با پروکسیها آسیب را کاهش میدهد. نامهای کاربری جداگانه برای وظایف، محدودیتهای ترافیک و اتصال به IP، نشت را از «تمام موجودی رفت» به «یک نام کاربری را لغو کردم» تبدیل میکند.
یک طرف دیگر نیز وجود دارد که باتنتها به طور منظم نشان میدهند: دستگاههای تصرف شده دیگر خود به «پروکسیهای مقیم» شبکههای مشکوک تبدیل میشوند. بنابراین برای پارس، بهتر است ترافیک را از ارائهدهندهای با منبع واضح مجموعه بگیرید. برای اکثر وظایف جمعآوری دادهها، پروکسیهای مقیم با پرداخت به ازای گیگابایت مناسب هستند، جایی که مصرف هر پروکسی در پنل قابل مشاهده است. برای وظایف خدماتی بدون حفاظت سخت ضد ربات، پروکسیهای دادهمرکز ارزانتر کافی است.
نتیجهگیری
CARBONATO نه از آسیبپذیریهای روز صفر استفاده میکند و نه از اکسپلویتهای پیچیده. او از درب وارد میشود که مالکان سرورها خودشان باز کردهاند: TCP ۲۳۷۵ بدون رمز عبور. جدید در آن این است که درون آن یک عامل هوش مصنوعی کار میکند که به او دستور داده شده است که ابتدا کلیدهای مدلها را بگیرد. برای کسانی که دادهها را در VPSهای خود جمعآوری میکنند، نتیجه عملی است. API Docker را ببندید، پورتهای خدماتی را بر روی ۱۲۷.۰.۰.۱ منتشر کنید، کلیدهای LLM و پروکسی را بر اساس وظایف با محدودیتهای هزینه تقسیم کنید. این ۱۵ دقیقه کار است و پس از آن سرور شما برای چنین باتنتهایی به هدفی غیرجذاب تبدیل میشود.
