Безопасность. Атака Arithmetic
Уязвимости целочисленного переполнения, как и в других языках, возникают из-за ограниченного размера памяти, выделенного на переменную. Максимальное значение для переменной типа uint (uint256) равно 2256−1, минимальное — 0. Выйти за эти границы не получится: значение либо обнулится (при переполнении вверх), либо станет максимальным (при переполнении вниз).
Очень хорошо про этот процесс было рассказано в этом видео.
Для примера можно привести такую функцию:
function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) {
uint cnt = _receivers.length;
uint256 amount = uint256(cnt) * _value;
require(cnt > 0 && cnt <= 20);
require(_value > 0 && balances[msg.sender] >= amount);
balances[msg.sender] = balances[msg.sender].sub(amount);
for (uint i = 0; i < cnt; i++) {
balances[_receivers[i]] = balances[_receivers[i]].add(_value);
Transfer(msg.sender, _receivers[i], _value);
}
return true;
}
Функция batchTransfer() перечисляет заданное в _value количество ether на адреса из массива _receivers. Обрати внимание на строку вычисления amount, переполнение в которой никак не проверяется. Если задать значение _value равным 2256 / _receivers.length, то в результате переполнения amount примет значение 0. Обе проверки далее пройдут успешно, в том числе и проверка того, что баланс отправителя больше amount. В итоге балансы получателей будут пополнены на величину _value. Если получателей было два, то каждый из них получит по
2^256/2=2^255=0x8000000000000000000000000000000000000000000000000000000000000000 токенов.
Для исключения подобных уязвимостей рекомендуется использовать библиотеку SafeMath от OpenZeppelin.
#arithmetic #time #безопасность
Уязвимости целочисленного переполнения, как и в других языках, возникают из-за ограниченного размера памяти, выделенного на переменную. Максимальное значение для переменной типа uint (uint256) равно 2256−1, минимальное — 0. Выйти за эти границы не получится: значение либо обнулится (при переполнении вверх), либо станет максимальным (при переполнении вниз).
Очень хорошо про этот процесс было рассказано в этом видео.
Для примера можно привести такую функцию:
function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) {
uint cnt = _receivers.length;
uint256 amount = uint256(cnt) * _value;
require(cnt > 0 && cnt <= 20);
require(_value > 0 && balances[msg.sender] >= amount);
balances[msg.sender] = balances[msg.sender].sub(amount);
for (uint i = 0; i < cnt; i++) {
balances[_receivers[i]] = balances[_receivers[i]].add(_value);
Transfer(msg.sender, _receivers[i], _value);
}
return true;
}
Функция batchTransfer() перечисляет заданное в _value количество ether на адреса из массива _receivers. Обрати внимание на строку вычисления amount, переполнение в которой никак не проверяется. Если задать значение _value равным 2256 / _receivers.length, то в результате переполнения amount примет значение 0. Обе проверки далее пройдут успешно, в том числе и проверка того, что баланс отправителя больше amount. В итоге балансы получателей будут пополнены на величину _value. Если получателей было два, то каждый из них получит по
2^256/2=2^255=0x8000000000000000000000000000000000000000000000000000000000000000 токенов.
Для исключения подобных уязвимостей рекомендуется использовать библиотеку SafeMath от OpenZeppelin.
#arithmetic #time #безопасность
👍1