Nahack ng Notional Finance para sa $1.73M dahil sa vulnerability ng integer overflow

iconMetaEra
I-share
AI summary iconSummary
Isang pag-eksplota ng $1.73 milyon ang tumama sa Notional Finance noong Setyembre 4, 2026, habang ang mga attacker ay nagamit ang integer overflow sa Escrow contract. Ang kakulangan sa function na ExchangeRate._convertToETH ay nagbigay-daan sa paglikha ng fCash position nang walang sapat na collateral. Ang insidente ay nagpapakita ng kahalagahan ng malakas na ratio ng panganib sa kita sa mga DeFi strategy. Ang mga trader na gumagamit ng TA para sa crypto ay dapat manatiling alerto dahil maaaring magbago nang mabilis ang mga dinamika ng merkado dahil sa ganitong mga vulnerability.

May-akda: Jiu Jiu

I-edit: 77

Background

Noong Septiyembre 4, 2026, ang kilalang decentralized lending platform na Notional Finance ay nasakop, na nagresulta sa pagkawala ng halos $1.73 milyon. Narito ang detalyadong pagsusuri ng seguridad team ng Slow Mist tungkol sa insidente na ito:

Panimulang kaalaman

Sa Notional Finance V1, ang fCash ay maaaring maunawaan bilang isang pautang na pera na may katapusan na petsa. Ang cash receiver ay tatanggap ng bayad sa katapusan, habang ang cash payer ay magbabayad sa katapusan. Ang protokolo ay nagtatala ng parehong posisyon sa Portfolio, at pagkatapos ay sinusuri ang kalusugan ng isang account kung maaari itong bumuo ng posisyon sa pamamagitan ng pagsusuri ng libreng collateral.

Ang safeTransferFrom ng ERC1155Trade ay nagtataglay ng tungkulin sa pagtatala ng mga aset. Kapag ang uri ng aset na ipinapadala ay kasama sa cash receiver, ang kontrato ay magtatawag ng Portfolios.mintfCashPair, samantalang itatala ang isang obligasyon sa payer at isang katumbas na pananalig sa receiver. Ang pagtawag na ito ay tila isang ERC1155 transfer, ngunit ang resulta ay isang pares na pagmimint ng fCash.

Pagkatapos isulat ang bagong posisyon sa Portfolio, kailangan ng pagkalkula at pagsusuri ng libreng collateral. Ang RiskFramework contract ay muna mag-aagwat ng fCash liability ng payer bilang isang may signong int256, at pagkatapos ay i-convert ang bawat balanse ng coin sa ETH para sa pag-aagwat. Ang negatibong bilang ay nangangahulugan ng kasaligan na kailangang bayaran, habang ang positibong bilang ay nangangahulugan ng pera o pananalig na may-ari ng account. Ang resulta ng kalkulasyong ito ang nagdedesisyon kung maaari o hindi ang transaksyon.

Pagkatapos matapos ang posisyon, gagamitin ng Portfolio ang portfolioSettleCash function ng Escrow upang i-convert ang matatapos na fCash sa cash balance. Pagkatapos, gagawa ang account ng withdrawal function upang kunin ang kaugnay na DAI o USDC assets mula sa Escrow.

Pangunahing dahilan

Ang pangunahing butas sa pagsalakay na ito ay nasa ExchangeRate._convertToETH na ginamit sa Escrow implementation contract, kung saan may isang code na direktang kumonbert ng absolute value ng signed integer sa uint128.

Nagtatayo ang attacker ng dalawang magkakaparehong posisyon ng utang na may parehong payer, na may halaga na 1 at uint128.max. Kapag idinagdag ang dalawang utang, tumutumbok ito sa 2^128. Dahil ang pagbabayad ng payer ay isinasaalang-alang bilang negatibo sa pagkalkula ng panganib, ang mahalagang parameter na ipinapasa ng Escrow sa convertBalancesToETH ay -2^128.

Gayunpaman, ang bersyon ng Solidity na ginagamit sa kontratong ito ay 0.6.x, kaya ang absolute value na 2^128 ay maaaring mag-overflow at maging 0 kapag ito ay ilarawan bilang uint128, kaya’t ang utang na ito ay hindi napapasok sa resulta na nakabatay sa ETH.

Sa huling bahagi ng mintfCashPair function, ang tanging kinakailangan ay ang libreng collateral ng payer ay mas malaki o katumbas ng zero, kaya sa pagkakaroon ng overflow na naging zero, maaari pa ring lumampas sa pagsusuri na ito, at ang isang account na walang sapat na assets upang takpan ang kanyang utang ay maaari pa ring magtatag ng posisyon.

Pagsusuri ng mga hakbang ng pag-atake

1. Sa前置交易 (0xe1589a19…d60a), ang attacker ay unang nilikha ang maraming auxiliary contracts at tinawag ang setApprovalForAll function ng ERC1155Trade contract upang bigyan ng pahintulot ang auxiliary contracts; gayundin ay na-query na agad ang dalawang CashMarket expiry dates at kinalkula ang mga halaga ng tatlong AssetId parameters na kailangan sa susunod na mga aksyon.

2. Agad pagkatapos, ang attacker ay tumawag sa function na safeTransferFrom ng ERC1155Trade contract upang mag-mint ng isang fCash pair na may halaga na 1, na may cashGroupId na 2 para sa bond asset at expiration timestamp na 1788480000 (Setyembre 4, 2026, 8:00 AM). Dito ay tinatawag ang internal function na _upsertAsset upang i-update ang liability at inaasahang kita para sa from address (attacker contract) at to address (receiver contract 1).

Pagkatapos matapos ang paggawa ng pair, agad na titingnan ng Portfolios ang libreng collateral ng attack contract, at dahil maliit ang dami ng unang paggawa, ang pagkalkula nito sa ETH batay sa kasalukuyang halaga at precision ay iiround off sa zero, kaya nakakapasa ang unang pag-check.

3. Pagkatapos ay muli niyang tinawag ang safeTransferFrom na punsiyon ng ERC1155Trade na kontrata upang magmint ng isang fCash pair na may halaga na uint128.max, kung saan ang cashGroupId ng kaugnay na bond asset ay 2, ngunit ang timestamp ng maturity ay 1796256000 (Disyembre 3, 2026, 8:00 AM).

May isang detalye kung saan ang attacker ay nag-mint ng mga bond asset na may iba’t ibang maturity date sa dalawang magkakaibang address. Ito ay dahil habang ina-update ang liability ng from address, kung ang bond asset ay magkakapareho, diretso itong idadagdag, na magdudulot ng revert sa pagproseso ng addition dahil sa overflow (gumagamit ang contract ng SafeMath library).

4. Pagkatapos i-update ang mga obligasyon at inaasahang kita para sa from address (attack contract) at to address (receive contract 2), ang mintfCashPair function ay tatawag sa freeCollateral function upang kalkulahin ang net collateral position ng from address at i-check kung ito ay mas malaki o katumbas ng 0 upang maging healthy.

Kung saan muna ay idadagdag ang kabuuang utang ng dalawang pagmimina mula sa from address sa function na getRequirement sa RiskFramework contract:

Ang kinalabasan ay -2^128, at susundan ito ng pagtawag sa function na convertBalancesToETH ng Escrow contract upang i-convert ang halagang ito sa ETH, at ang convertBalancesToETH function ay tatawag din sa function na _convertToETH ng ExchangeRate library para sa pagproseso:

Sa pagsubaybay sa function na _convertToETH, makikita na ito ay unang kukuha ng absolute value ng balance bago gamitin ang uint128 upang i-convert ang 256-bit na halaga sa 128-bit, samantalang ang kabuuang halaga ng utang mula sa itaas ay -2^128; kapag kinuha ang absolute value nito, ang 2^128 ay magiging sobra sa limitasyon kapag isinasagawa ang pagsasaliksik na uint128(), na nagreresulta sa overflow at pagiging 0. Ibig sabihin nito, ang protokolo ay maliit na naniniwala na ang libreng collateral position ng from address ay 0 at ito ay malusog, kaya ito ay nakapasa sa huling pagsusuri sa function na mintfCashPair.

5. Pagkatapos ay tinanggap ng Contract 2 ang posisyon at ikinabahagi ito sa dalawang karagdagang contract; ang dalawang safeTransferFrom na ito ay patuloy na pumapasok sa function na mintfCashPair. Gayunpaman, dahil ang payer ngayon ay ang Contract 2 na tinanggap noong pangalawang pagmimint, na may malaking posisyon ng inaasahang kita mula sa hakbang na nakaraan, ang pagsusuri sa panganib ay itinuturing ito bilang positibong krédito, kaya nagdaan ito sa pagsusuri ng collateral, at kaya naman ay nakakuha ang dalawang karagdagang contract ng receiver fCash na maaaring palitan sa pera pagkatapos ng katapusan.

6. Pagkatapos ay isinagawa ng attacker ang pangalawang opisyal na trade para sa pagkuha ng kita, kung saan tinapos ang mga kaukulang karapatan ng dalawang posisyon mula sa nakaraang trade, dinagdagan ang cash balance ng mga kaugnay na asset, at pagkatapos ay tinawag ang withdraw function ng Escrow contract upang i-withdraw ang kanilang mga asset at makakuha ng kita.

Summary

Ang pangunahing punto sa insidente na ito ay ang attacker na una nang gumamit ng dalawang hiwalay na posisyon upang i-compile ang kabuuang utang ng payer sa 2^128, at pagkatapos ay ipinadala ang utang na ito sa Escrow upang i-convert ito sa ETH. Gamit ang vulnerability sa overflow sa pagkakatype, ang resulta ay binawasan hanggang sa zero, kaya ang pagsusuri sa panganib ay pinayagan.

Ninilay ng security team ng SlowMist na ang mga project owner ay dapat magkaroon ng range check bago magawa ang type conversion; tatanggihan agad ang anumang resulta na hihigit sa type(uint128).max. Samantala, dapat magdagdag ng extreme value testing sa lahat ng mga boundary na may kinalaman sa signed amount, precision scaling, at asset denomination, lalo na ang mga input tulad ng uint128.max, uint128.max + 1, at absolute value ng negative numbers. Maaaring sundin o gamitin ang Openzeppelin’s SafeCast library para sa pag-convert.

Disclaimer: Ang information sa page na ito ay maaaring nakuha mula sa mga third party at hindi necessary na nagre-reflect sa mga pananaw o opinyon ng KuCoin. Ibinigay ang content na ito para sa mga pangkalahatang informational purpose lang, nang walang anumang representation o warranty ng anumang uri, at hindi rin ito dapat ipakahulugan bilang financial o investment advice. Hindi mananagot ang KuCoin para sa anumang error o omission, o para sa anumang outcome na magreresulta mula sa paggamit ng information na ito. Maaaring maging risky ang mga investment sa mga digital asset. Pakisuri nang maigi ang mga risk ng isang produkto at ang risk tolerance mo batay sa iyong sariling kalagayang pinansyal. Para sa higit pang information, mag-refer sa aming Terms ng Paggamit at Disclosure ng Risk.