Взлом Solidity: целочисленное переполнение и недополнение
Немного базовых знаний
Целое число — это целое число, поэтому оно не имеет дробных частей. Целые числа могут быть как положительными, так и отрицательными. Существует множество различных диапазонов целых чисел, которые могут использоваться в языках программирования, но Solidity использует диапазон 256-битных целых чисел без знака. Это означает, что числа начинаются с 0 и идут до 115792089237316195423570985008687907853269984665640564039457584007913129639935 (в десятичной системе).
Solidity выдаст ошибку, если вы попытаетесь присвоить значение, не являющееся целым числом, переменной, объявленной как единица. Вы можете проверить, что происходит, попробовав установить логическую (true/false) переменную, равную целому числу.
Когда вы используете целые числа с математическими операциями, вам нужно знать, что происходит, когда значения становятся слишком большими или маленькими для своего диапазона. Переполнение происходит, когда превышено максимальное значение, а недополнение происходит, когда превышено минимальное значение.
Solidity — это контрактно-ориентированный язык высокого уровня для реализации смарт-контрактов. На него повлияли C++, Python и JavaScript, и он предназначен для виртуальной машины Ethereum (EVM). Solidity имеет статическую типизацию, поддерживает наследование, библиотеки и сложные определяемые пользователем типы среди других функций.
Целочисленное переполнение и недополнение
Целочисленное переполнение и недополнение — это уязвимости, которые могут привести к краже средств или другой информации в смарт-контракте. В этой статье объясняется, что это за уязвимости, почему их важно понимать и как их избежать.В Solidity целые числа подписываются, если они не отмечены буквой «U» в верхнем регистре в конце. Целое число без знака имеет тип uint; целое число со знаком имеет тип int.
Диапазон значений 256-битного числа со знаком (int256) — от -(2²⁵⁵) до 2²⁵⁵ — 1. Диапазон значений 256-битного числа без знака (uint256) — от 0 до 2²⁵⁶ — 1.
Пример кода контракта
Код:
function deposit() public payable{
_balance[msg.sender] = _balance[msg.sender].add(msg.value); //Add method of SafeMath library is used to add two numbers and throws an error if the calculation overflows/underflows a type
}
function withdraw(uint256 amount) public {
require(_balance[msg.sender] >= amount, “Insufficient balance”); //checking for sufficient balance before withdrawing funds
_balance[msg.sender] = _balance[msg.sender].sub(amount); //Subtract method of SafeMath library is used to subtract two numbers and throws an error if the calculation overflows/underflows a type
msg.sender.transfer(amount); //send funds back to the caller address
}
function withdrawAll() public {
uint256 amount = _balance[msg.sender]; //store balance in amount variable so that we can use it after resetting the mapping value to 0 as part of withdrawAll process
_balance[msg.sender] = 0; //reset the mapping value after storing current balance in temporary variable (amount)
msg.sender.transfer(amount); // send entire balance back to the caller address by using transfer method on msg object which represents sender address (caller’s address)
}
Векторы атаки
Есть несколько способов, которыми вы можете использовать целочисленное недополнение/переполнение для получения желаемых математических результатов.- Вызовите функцию с большим количеством. Если вы дадите функции входное значение uint256(2)²⁵⁶ — 1, она вернет 0. Это простой способ «обнулить» баланс!
- Вызовите функцию с отрицательной суммой несколько раз. Если вы вызовете функцию три раза с (uint256(-1)), она добавит 2⁸ — 3, в результате чего получится 2⁸ — 1, и если бы мы вызвали это снова, это привело бы к 0! Вы можете повторить это, чтобы создать любое число меньше 2⁸, используя всего 8 вызовов! Та же идея работает и для 256-битных чисел, если в вашем контракте достаточно газа.
- Вызовите функцию с отрицательной суммой 101 раз или более. Вызов transfer(uint(-1)) 101 раз установит ваш баланс на MAX_UINT вместо MIN_UINT, поскольку добавление 101 * (-1) эквивалентно вычитанию 101 из вашего баланса, который переполняется при 255 и становится MAX_UINT.
Будьте осторожны при использовании целых чисел в коде смарт-контракта!
Язык программирования Solidity был разработан для помощи в написании смарт-контрактов Ethereum. Сегодня это самый популярный выбор для написания смарт-контрактов.Solidity — это язык, который компилируется в байт-код виртуальной машины Ethereum (EVM) и сохраняется в блокчейне. EVM — это среда выполнения, которая выполняет код смарт-контракта и управляет его состоянием, но в ней отсутствуют некоторые функции, которые мы считаем само собой разумеющимися при работе с другими языками программирования, такими как JavaScript. В частности, в Solidity нет встроенной поддержки целых чисел без знака, поэтому, если вы не будете осторожны при их использовании, ваш контракт может быть уязвим для ошибок целочисленного переполнения/опустошения!
Целочисленное переполнение/недополнение происходит, когда вы пытаетесь сохранить что-то большее, чем может поместиться в целочисленной переменной, или меньше 0 в целочисленной переменной без знака. Каждый раз, когда это происходит, вместо получения ожидаемого результата переменной будет присвоено непреднамеренное значение.
Переведена вот статья
I like it!