Вось як знайсці 10 мільёнаў долараў, прачытаўшы blockchain

Два тыдні таму энтузіяст Голема і ўладальнік GNT паведамілі аб дзіўнай памылцы пры перадачы транзакцый на GNT. Вывучыўшы дадзеныя, звязаныя з транзакцыяй, я выявіў, што ўзнікла праблема ў падрыхтоўцы дадзеных для транзакцыі праз абмен. "О, не," я падумаў, "гэтая памылка можа быць выкарыстана для ачысткі ўсяго рахунку ВНТ на біржы!"

Памылка сапраўды была віной фондавай біржы, але яна таксама была звязана з тым, як кантракты Ethereum бачаць уводныя дадзеныя транзакцый і ABI Solidity (напрыклад, як методыкі кантрактаў Solidity кадуюць і дэкадуюць аргументы). Такім чынам, гэта было не спецыфічна для GNT, але для ўсіх токенаў ERC20 і для іншых кантрактаў, якія маюць спосабы перадачы. Так, вы правільна прачыталі: гэта, магчыма, спрацавала б для ўсіх токенаў на базе Ethereum, пералічаных на гэтай біржы, калі толькі зняцце кіравалася такім жа чынам, як і GNT. Мы не ведаем, што гэта так, але мяркуем, што гэта было вельмі верагодна.

Кантракт Ethereum ABI

Кантракты на сыравіну Ethereum не маюць ні спосабаў, ні функцый. Метады - гэта функцыі моў высокага ўзроўню, такія як Solidity, і выкарыстаць кантракт Ethereum ABI, каб вызначыць, як байт-код кантракту дзеліцца на метады і як розныя тыпы аргументаў кадуюцца ў дадзеных уводу транзакцый. (Даведку можна знайсці на https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI.)

Для выкліку спосабу перадачы (адрас a, uint v) дамовы аб ВНП для пераводу 1 GNT на адрас 0xabcabcabcabcabcabcabcabcabcabcabcabcabca неабходна ўказаць 3 элемента дадзеных:

  • 4 байта, гэта метад ID: a9059cbb
  • 32 байта, дзе адрас прызначэння (20 байт) запоўнены вядучымі нулямі: 000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabcabca
  • 32 байта, гэта значэнне для перадачы, 1 х 10¹ & sup0;

Таму поўная здзелка будзе выглядаць так:

Дадзеныя ўводу транзакцый бясконцыя

Гэта адзін з больш хаатычных аспектаў віртуальнай машыны Ethereum, але вельмі важна, каб цалкам зразумець праблему. EVM можа счытваць байты любога зрушэння ўваходных дадзеных з дапамогай CALLDATALOADopcode. Калі дадзеныя ў гэтым зрушэнні не прадастаўляюцца стваральнікам транзакцыі ў рамках транзакцыі, EVM атрымлівае нулі ў якасці адказу. У той жа час кантракт з опкодам CALLDATASIZE можа праверыць фактычную даўжыню прадастаўленых уводных дадзеных транзакцый.

Памылка

Служба, якая рыхтуе дадзеныя для перадачы жэтонаў, мяркуе, што карыстальнікі будуць уводзіць 20-байтовыя адрасы, але даўжыня адрасоў не была праверана. У згаданай транзакцыі карыстальнік увёў недапушчальны адрас з меншай даўжынёй: 79735. Атрыманыя дадзеныя былі няправільнымі, паколькі аргумент адраса заняў 14,5 байт (12 байт для вядучых нулёў + 4,5 байта для ўводу карыстальніка). Калі быць дакладным, дадзеныя аб транзакцыях для платформы Ethereum былі добра, бо гаворка ідзе не пра дадзеныя транзакцый, за выключэннем таго, што плата за кожны байт. Адзінай прычынай пераводу жэтонаў дамовай аб ВНТ было тое, што сума ўгоды была недарэчна высокай (вышэй за агульную прапанову і, вядома, вышэй, чым баланс адраса. Уладальніку адраса сапраўды пашанцавала, што карыстальнік выкарыстаў такую ​​кароткую радок для адраса: З чымсьці (няўдача) карыстальнік зможа * выпадкова * апусціць адрас усіх БНТ і адправіць яго любому атрымальніку . Калі мы зразумелі, што памылка можа быць выкарыстана і для нападаў, яна была вельмі сур'ёзнай.

Магчымая атака

Як вы ўжо заўважылі, увод кароткага адраса перакладу змяняе значэнне колькасці лексем, якія трэба перадаць налева, павялічваючы значэнне. Таксама вельмі лёгка знайсці прыватны ключ для адраса Ethereum з нулямі ў канцы адраса, напрыклад. 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000.

Таму ўладальнік гэтага адрасу можа ўвесці 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa (прапусціць нулі) у службовым інтэрфейсе. Затым зламыснік можа замовіць перанос значэння X са службы на няправільны адрас. Гэта фактычна перанясе 16-бітнае зрушанае значэнне, я. H. 65536 разоў больш, чым X, на рахунак злачынца Ethereum.

Што мы зрабілі з гэтым?

Вызначыўшы магчымую атаку, мы звязаліся з біржай і паведамілі ім пра памылку. Гэта быў дзіўна складаны і раздражняльны працэс. Наш генеральны дырэктар Джуліян патэлефанаваў у службу падтрымкі, прадстаўнік якой не хацеў слухаць. Ён усё крычаў, што памылкі - гэта не яго справа, і адмовіўся ўзяць нас далей па ланцугу. Праз некалькі гадзін Алекс паспеў узяць нас да ўзроўню генеральнага дырэктара, і наша паведамленне перайшло. Атрымаўшы пацверджанне, што памылка была выпраўлена, мы пайшлі на іншыя біржы. Хоць у нас не было прычын меркаваць, што яны ўразлівыя, у нас таксама не было прычыны лічыць наадварот. Хоць мы павінны прызнаць, што мы не правяралі гэтага на іншых біржах і токенах, мы былі шакаваны і крыху спалохаліся, калі зразумелі магчымыя наступствы, калі хто-небудзь скарыстаўся гэтай памылкай для некалькіх токенаў на некалькіх біржах: увесь токен Ethereum Эканоміка і стартавая экасістэма могуць быць наладжаны гадамі.

Што Ethereum можа зрабіць з гэтым?

Я не думаю, што распрацоўшчыкі Ethereum могуць зрабіць значна больш, чым навучыць насельніцтва пра тое, як Ethereum працуе на самай справе. Тым не менш, мы можам прапанаваць дадатковыя праверкі, якія трэба дадаваць у будучых версіях Solidity, напрыклад, каб праверыць, ці працягласць уводу транзакцый адпавядае чаканым дадзеных для названага метаду кантракту.

Што павінна рабіць біржа?

  1. Праверце ўвод карыстальніка як мага бліжэй. Проста правяраючы даўжыню адраса, указанага карыстальнікам, яны абараняюцца ад апісанай атакі. Таксама праверце кантрольную суму Ethereum, калі яна маецца (гл. EIP55), альбо прымайце адрасы толькі з кантрольнымі сумамі. Гэта павялічвае бяспеку і зручнасць выкарыстання.
  2. Пераканайцеся, што дадзеныя транзакцый правільна закадзіраваны.
  3. Згенераваныя дадзеныя транзакцый таксама могуць быць прааналізаваны назад і параўнаны з паказаным карыстацкім уводам.
  4. Праверце, ці адпавядаюць чаканым значэнням іншыя параметры, такія як кошт газу, цана газу і адрас прызначэння згенераванай транзакцыі.