DeFi AMM Hitilafu za Uhasibu & Virtual Balance Cache Exploitation

Tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Jifunze na fanya mazoezi ya Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

Muhtasari

Yearn Finance’s yETH pool (Nov 2025) ilionyesha jinsi caches zinazohifadhi gesi ndani ya AMMs tata zinaweza kutumika kama silaha pale hazipozoelekezwa wakati wa mabadiliko ya hali za mipaka. The weighted stableswap pool inafuatilia hadi 32 liquid staking derivatives (LSDs), inazitafsiri kuwa ETH-equivalent virtual balances (vb_i = balance_i × rate_i / PRECISION), na kuhifadhi yale maadili katika packed storage array packed_vbs[]. Wakati all LP tokens are burned, totalSupply inashuka kwa usahihi hadi sifuri lakini cache za packed_vbs[i] zilibaki zimehifadhi maadili makubwa ya kihistoria. Mtoa amana aliyejumuisha baadaye alitendewa kama “first” liquidity provider ingawa cache ilikuwa bado ina phantom liquidity, kumruhusu mshambuliaji kutengeneza takriban ~235 septillion yETH kwa 16 wei tu kabla ya kuondoa karibu ≈USD 9M katika dhamana ya LSD.

Viungo kuu:

  • Derived-state caching: inazuia utafutaji wa oracle ghali kwa kuhifadhi virtual balances na kuzibadilisha kwa hatua.
  • Missing reset when supply == 0: remove_liquidity() upunguzaji wa kiwango uliobaki uliwaacha mabaki yasiyo-sifuri kwenye packed_vbs[] baada ya kila mzunguko wa uondoaji.
  • Initialization branch trusts the cache: add_liquidity() hujita _calc_vb_prod_sum() na kwa urahisi inasoma packed_vbs[] wakati prev_supply == 0, ikidhani cache pia imefanywa sifuri.
  • Flash-loan financed state poisoning: deposit/withdraw loops ziliongeza mabaki ya uviringishaji bila kufungwa kwa mtaji, kuruhusu over-mint ya kuangamiza katika njia ya “first deposit”.

Cache design & missing boundary handling

Mtiririko hatarishi umefupishwa hapa chini:

function remove_liquidity(uint256 burnAmount) external {
uint256 supplyBefore = totalSupply();
_burn(msg.sender, burnAmount);

for (uint256 i; i < tokens.length; ++i) {
packed_vbs[i] -= packed_vbs[i] * burnAmount / supplyBefore; // truncates to floor
}

// BUG: packed_vbs not cleared when supply hits zero
}

function add_liquidity(Amounts calldata amountsIn) external {
uint256 prevSupply = totalSupply();
uint256 sumVb = prevSupply == 0 ? _calc_vb_prod_sum() : _calc_adjusted_vb(amountsIn);
uint256 lpToMint = pricingInvariant(sumVb, prevSupply, amountsIn);
_mint(msg.sender, lpToMint);
}

function _calc_vb_prod_sum() internal view returns (uint256 sum) {
for (uint256 i; i < tokens.length; ++i) {
sum += packed_vbs[i]; // assumes cache == 0 for a pristine pool
}
}

Kwa sababu remove_liquidity() ilitumia tu upunguzaji kwa uwiano, kila mzunguko uliacha fixed-point rounding dust. Baada ya ≳10 mizunguko ya depoziti/kunyakua, mabaki hayo yaliokusanywa katika salio kubwa za phantom virtual wakati salio za token kwenye mnyororo zilikuwa karibu tupu. Kuzima hisa za mwisho za LP kuliweka totalSupply kuwa sifuri lakini caches zilibaki zimejazwa, zikoiweka itifaki kwa initialization iliyoharibika.

Mpango wa exploit (somo la kesi yETH)

  1. Flash-loan working capital – Kopa wstETH, rETH, cbETH, ETHx, WETH, n.k. kutoka Balancer/Aave ili kuepuka kufunga mtaji wakati wa kuathiri pool.
  2. Poison packed_vbs[] – Rudia mizunguko ya depoziti na uondoaji kwa mali nane za LSD. Kila uondoaji wa sehemu hukata packed_vbs[i] − vb_share, ukiwaacha mabaki >0 kwa tokeni. Kurudia mzunguko kunapanua salio za phantom sawa na ETH bila kuibua shaka kwa sababu salio halisi kwa karibu zinagharimu nje.
  3. Force supply == 0 – Kausha (burn) kila tokeni ya LP iliyobaki ili pool iamini kuwa tupu. Upungufu wa utekelezaji unaacha packed_vbs[] iliyotumwa isiyoguswa.
  4. Dust-size “first deposit” – Tuma jumla ya 16 wei iliyogawanywa kwenye slots za LSD zinazotumika. add_liquidity() inaona prev_supply == 0, inaendesha _calc_vb_prod_sum(), na inasoma cache iliyozee badala ya kuhesabu upya kutoka kwa salio halisi. Hivyo hesabu ya mint inafanya kazi kana kwamba trilioni za USD zingeingia, ikitoa ~2.35×10^26 yETH.
  5. Drain & repay – Rejea nafasi ya LP iliyopanuliwa kwa LSD zote zilizohifadhiwa, badilisha yETH→WETH kwenye Balancer, ubadilishe kuwa ETH kupitia Uniswap v3, lirudishe flash loans/ada, na safisha faida (km, kupitia Tornado Cash). Faida ya net ≈USD 9M huku tu 16 wei ya fedha binafsi zilikuwaga pool.

Masharti ya jumla ya exploitation

Unaweza kutia matumizi mabaya AMMs sawa wakati mambo yafuatayo yote yanatafanyika:

  • Cached derivatives of balances (virtual balances, TWAP snapshots, invariant helpers) hudumu kati ya miamala kwa ajili ya kuokoa gesi.
  • Partial updates truncate matokeo (floor division, fixed-point rounding), kuruhusu mshambuliaji kukusanya mabaki ya hali kupitia mizunguko ya simetriki ya depoziti/kuondoa.
  • Boundary conditions reuse caches badala ya recomputation ya ukweli wa chini, hasa wakati totalSupply == 0, totalLiquidity == 0, au muundo wa pool unapofanywa upya.
  • Minting logic lacks ratio sanity checks (mf., kutokuwepo kwa mipaka ya expected_value/actual_value) hivyo depoziti ya vumbi inaweza ku-mint karibu kabisa hesabu ya kihistoria.
  • Cheap capital is available (flash loans au mikopo ya ndani) ili kufanya miongo kadhaa ya urekebishaji wa hali ndani ya muamala mmoja au kundi lililopangwa kwa karibu.

Orodha ya ukaguzi wa uhandisi wa kinga

  • Explicit resets when supply/lpShares hit zero:
if (totalSupply == 0) {
for (uint256 i; i < tokens.length; ++i) packed_vbs[i] = 0;
}

Tumia matibabu sawa kwa kila accumulator iliyohifadhiwa inayotokana na salio au data ya oracle.

  • Recompute on initialization branches – Wakati prev_supply == 0, puuzilia caches kabisa na jenga tena virtual balances kutoka kwa salio halisi za token + viwango vya oracle vinavyofanya kazi.
  • Minting sanity bounds – Revert ikiwa lpToMint > depositValue × MAX_INIT_RATIO au ikiwa muamala mmoja una-mint >X% ya hesabu ya kihistoria wakati depoziti za jumla ziko chini ya threshold ya chini.
  • Rounding-residue drains – Kusanya vumbi kwa tokeni kwa sink (treasury/burn) ili marekebisho ya uwiano yanayorudiwa yasivurunge caches mbali na salio halisi.
  • Differential tests – Kwa kila mabadiliko ya hali (add/remove/swap), rekebisha invariant sawa off-chain kwa hisabati ya ufanisi mkubwa na thibitisha usawa ndani ya epsilon kali hata baada ya kuondolewa kwa liquidity kamili.

Ufuatiliaji na jibu

  • Multi-transaction detection – Fuata mfululizo wa matukio ya karibu-simetriki ya depoziti/kuondoa ambayo yanaiacha pool na salio ndogo lakini cache kubwa ya hali, iliyofuatiwa na supply == 0. Vigunduzi vya anomali vya muamala mmoja hupoteza kampeni hizi za poisoning.
  • Runtime simulations – Kabla ya kutekeleza add_liquidity(), jenga upya virtual balances kutoka mwanzo na linganisha na jumla za cache; revert au simamisha ikiwa deltas zinazidi threshold ya basis-point.
  • Flash-loan aware alerts – Tandaza alama kwa miamala inayochanganya flash loans kubwa, uondoaji wa pool kwa kiwango kikamilifu, na depoziti ya ukubwa wa vumbi; zuia au uhitaji idhini ya mkono.

References

Tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Jifunze na fanya mazoezi ya Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks